content: /**
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package org.apache.aurora.scheduler.http;
  
  import java.io.StringWriter;
  import java.util.List;
  import java.util.Optional;
  import java.util.Set;
  
  import javax.ws.rs.FormParam;
  import javax.ws.rs.GET;
  import javax.ws.rs.POST;
  import javax.ws.rs.Path;
  import javax.ws.rs.Produces;
  import javax.ws.rs.core.MediaType;
  
  import com.google.common.collect.FluentIterable;
  import com.google.common.collect.Lists;
  import com.google.common.collect.Ordering;
  
  import org.apache.aurora.common.util.templating.StringTemplateHelper;
  import org.apache.aurora.common.util.templating.StringTemplateHelper.TemplateException;
  import org.apache.commons.lang.StringUtils;
  import org.slf4j.LoggerFactory;
  
  import ch.qos.logback.classic.Level;
  import ch.qos.logback.classic.Logger;
  import ch.qos.logback.classic.LoggerContext;
  
  /**
   * Servlet that allows for dynamic adjustment of the logging configuration.
   *
   * @author William Farner
   */
  @Path("/logconfig")
  public class LogConfig {
    private static final List<String> LOG_LEVELS = Lists.newArrayList(
        Level.OFF.levelStr,
        Level.ERROR.levelStr,
        Level.WARN.levelStr,
        Level.INFO.levelStr,
        Level.DEBUG.levelStr,
        Level.TRACE.levelStr,
        Level.ALL.levelStr,
        "INHERIT" // Display value for a null level, the logger inherits from its ancestor.
    );
  
    private final StringTemplateHelper template =
        new StringTemplateHelper(getClass(), "logconfig", false);
  
    @POST
    @Produces(MediaType.TEXT_HTML)
    public String post(
        @FormParam("logger") String loggerName,
        @FormParam("level") String loggerLevel) throws TemplateException {
  
      Optional<String> configChange = Optional.empty();
      if (loggerName != null && loggerLevel != null) {
        Logger logger = (Logger) LoggerFactory.getLogger(loggerName);
        Level newLevel = Level.toLevel(loggerLevel, null);
        logger.setLevel(newLevel);
  
        configChange = Optional.of(String.format("%s level changed to %s", loggerName, loggerLevel));
      }
  
      return displayPage(configChange);
    }
  
    @GET
    @Produces(MediaType.TEXT_HTML)
    public String get() throws TemplateException {
      return displayPage(Optional.empty());
    }
  
    protected String displayPage(Optional<String> configChange) throws TemplateException {
      StringWriter writer = new StringWriter();
  
      template.writeTemplate(writer, stringTemplate -> {
        if (configChange.isPresent()) {
          stringTemplate.setAttribute("configChange", configChange.get());
        }
  
        LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
  
        Set<LoggerConfig> loggers = FluentIterable.from(context.getLoggerList())
            .transform(logger -> new LoggerConfig(
                logger.getName(),
                Optional.ofNullable(logger.getLevel()).map(l -> l.levelStr).orElse("INHERIT")))
            .toSortedSet(Ordering.natural().onResultOf(LoggerConfig::getName));
  
        stringTemplate.setAttribute("loggers", loggers);
        stringTemplate.setAttribute("levels", LOG_LEVELS);
      });
  
      return writer.toString();
    }
  
    private static class LoggerConfig {
      private final String name;
      private final String level;
  
      LoggerConfig(String name, String level) {
        this.name = name;
        this.level = StringUtils.isBlank(level) ? "INHERIT" : level;
      }
  
      public String getName() {
        return name;
      }
  
      public String getLevel() {
        return level;
      }
    }
  }
  