package com.opentable.logging;

import javax.annotation.PostConstruct;
import javax.inject.Inject;

import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;

import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Appender;
import ch.qos.logback.core.filter.Filter;

public class AttachLogFilter {

    private final Filter<ILoggingEvent> filter;
    private final String configKey;

    private LoggerContext context;
    private String loggerName = org.slf4j.Logger.ROOT_LOGGER_NAME;
    private String appenderName;
    private boolean enabled = true;

    private AttachLogFilter(Filter<ILoggingEvent> filter, String configKey) {
        this.filter = filter;
        this.configKey = configKey;
    }

    @Inject
    AttachLogFilter provideEnvironment(Environment env) {
        enabled = env.getProperty(configKey, boolean.class, false);
        return this;
    }

    @PostConstruct
    public void attach() {
        if (!enabled) {
            return;
        }
        if (context == null) {
            context = (LoggerContext) LoggerFactory.getILoggerFactory();
        }

        final Logger attachLogger = context.getLogger(loggerName);

        if (attachLogger == null) {
            throw new IllegalArgumentException("Could not find logger " + loggerName);
        }

        if (appenderName != null) {
            doAttach(attachLogger.getAppender(appenderName));
            return;
        }

        attachLogger.iteratorForAppenders()
            .forEachRemaining(this::doAttach);
    }

    private void doAttach(Appender<ILoggingEvent> appender) {
        if (appender != null) {
            appender.addFilter(filter);
            LoggerFactory.getLogger(AttachLogFilter.class).info("Attached access log filter to {} '{}'", appender, appenderName);
        } else {
            throw new IllegalStateException("Could not attach access log filter to appender " + appenderName);
        }
    }

    public static AttachLogFilter attach(Filter<ILoggingEvent> filter, String configKey) {
        return new AttachLogFilter(filter, configKey);
    }

    public AttachLogFilter toLogger(String loggerName) {
        this.loggerName = loggerName;
        return this;
    }

    public AttachLogFilter toAppender(String appenderName) {
        this.appenderName = appenderName;
        return this;
    }

    public AttachLogFilter toContext(LoggerContext context) {
        this.context = context;
        return this;
    }
}

@@ -25,16 +25,44 @@
 gging;%0A%0A
+import java.util.Iterator;%0A%0A
 import j
@@ -446,17 +446,16 @@
 ilter %7B%0A
-%0A
     priv
@@ -1070,62 +1070,8 @@
 ) %7B%0A
-        if (!enabled) %7B%0A            return;%0A        %7D%0A
     
@@ -1173,32 +1173,204 @@
 y();%0A        %7D%0A%0A
+        if (!enabled) %7B%0A            LoggerFactory.getLogger(AttachLogFilter.class).debug(%22Not attaching %7B%7D due to '%7B%7D'%22, filter, configKey);%0A            return;%0A        %7D%0A%0A
         final Lo
@@ -1691,16 +1691,57 @@
 %0A       
+ Iterator%3CAppender%3CILoggingEvent%3E%3E iter =
  attachL
@@ -1768,16 +1768,18 @@
 enders()
+;%0A
 %0A       
@@ -1779,20 +1779,159 @@
         
-    
+if (!iter.hasNext()) %7B%0A            throw new IllegalStateException(%22expecting at least one appender attached to root%22);%0A        %7D%0A%0A        iter
 .forEach
@@ -2172,23 +2172,16 @@
 ttached 
-access 
 log filt
@@ -2178,24 +2178,27 @@
 d log filter
+ %7B%7D
  to %7B%7D '%7B%7D'%22
@@ -2198,16 +2198,24 @@
 %7D '%7B%7D'%22,
+ filter,
  appende
@@ -2315,15 +2315,8 @@
 ach 
-access 
 log 

improve messaging, error handling