PageRenderTime 51ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/dropwizard-logging/src/main/java/io/dropwizard/logging/DefaultLoggingFactory.java

https://gitlab.com/gogo649/dropwizard
Java | 233 lines | 193 code | 37 blank | 3 comment | 8 complexity | b145b435b2771e1e7265299c8112d0da MD5 | raw file
  1. package io.dropwizard.logging;
  2. import ch.qos.logback.classic.Level;
  3. import ch.qos.logback.classic.Logger;
  4. import ch.qos.logback.classic.LoggerContext;
  5. import ch.qos.logback.classic.jmx.JMXConfigurator;
  6. import ch.qos.logback.classic.jul.LevelChangePropagator;
  7. import ch.qos.logback.classic.spi.ILoggingEvent;
  8. import ch.qos.logback.core.util.StatusPrinter;
  9. import com.codahale.metrics.MetricRegistry;
  10. import com.codahale.metrics.logback.InstrumentedAppender;
  11. import com.fasterxml.jackson.annotation.JsonIgnore;
  12. import com.fasterxml.jackson.annotation.JsonProperty;
  13. import com.fasterxml.jackson.annotation.JsonTypeName;
  14. import com.fasterxml.jackson.core.JsonProcessingException;
  15. import com.fasterxml.jackson.databind.JsonNode;
  16. import com.google.common.annotations.VisibleForTesting;
  17. import com.google.common.base.MoreObjects;
  18. import com.google.common.collect.ImmutableList;
  19. import com.google.common.collect.ImmutableMap;
  20. import io.dropwizard.jackson.Jackson;
  21. import io.dropwizard.logging.async.AsyncAppenderFactory;
  22. import io.dropwizard.logging.async.AsyncLoggingEventAppenderFactory;
  23. import io.dropwizard.logging.filter.LevelFilterFactory;
  24. import io.dropwizard.logging.filter.ThresholdLevelFilterFactory;
  25. import io.dropwizard.logging.layout.DropwizardLayoutFactory;
  26. import io.dropwizard.logging.layout.LayoutFactory;
  27. import javax.management.InstanceAlreadyExistsException;
  28. import javax.management.MBeanRegistrationException;
  29. import javax.management.MBeanServer;
  30. import javax.management.MalformedObjectNameException;
  31. import javax.management.NotCompliantMBeanException;
  32. import javax.management.ObjectName;
  33. import javax.validation.Valid;
  34. import javax.validation.constraints.NotNull;
  35. import java.io.PrintStream;
  36. import java.lang.management.ManagementFactory;
  37. import java.util.List;
  38. import java.util.Map;
  39. import java.util.concurrent.locks.ReentrantLock;
  40. import static java.util.Objects.requireNonNull;
  41. @JsonTypeName("default")
  42. public class DefaultLoggingFactory implements LoggingFactory {
  43. private static final ReentrantLock MBEAN_REGISTRATION_LOCK = new ReentrantLock();
  44. private static final ReentrantLock CHANGE_LOGGER_CONTEXT_LOCK = new ReentrantLock();
  45. @NotNull
  46. private Level level = Level.INFO;
  47. @NotNull
  48. private ImmutableMap<String, JsonNode> loggers = ImmutableMap.of();
  49. @Valid
  50. @NotNull
  51. private ImmutableList<AppenderFactory<ILoggingEvent>> appenders = ImmutableList.of(
  52. new ConsoleAppenderFactory<>()
  53. );
  54. @JsonIgnore
  55. private final LoggerContext loggerContext;
  56. @JsonIgnore
  57. private final PrintStream configurationErrorsStream;
  58. public DefaultLoggingFactory() {
  59. this(LoggingUtil.getLoggerContext(), System.err);
  60. }
  61. @VisibleForTesting
  62. DefaultLoggingFactory(LoggerContext loggerContext, PrintStream configurationErrorsStream) {
  63. this.loggerContext = requireNonNull(loggerContext);
  64. this.configurationErrorsStream = requireNonNull(configurationErrorsStream);
  65. }
  66. @VisibleForTesting
  67. LoggerContext getLoggerContext() {
  68. return loggerContext;
  69. }
  70. @VisibleForTesting
  71. PrintStream getConfigurationErrorsStream() {
  72. return configurationErrorsStream;
  73. }
  74. @JsonProperty
  75. public Level getLevel() {
  76. return level;
  77. }
  78. @JsonProperty
  79. public void setLevel(Level level) {
  80. this.level = level;
  81. }
  82. @JsonProperty
  83. public ImmutableMap<String, JsonNode> getLoggers() {
  84. return loggers;
  85. }
  86. @JsonProperty
  87. public void setLoggers(Map<String, JsonNode> loggers) {
  88. this.loggers = ImmutableMap.copyOf(loggers);
  89. }
  90. @JsonProperty
  91. public ImmutableList<AppenderFactory<ILoggingEvent>> getAppenders() {
  92. return appenders;
  93. }
  94. @JsonProperty
  95. public void setAppenders(List<AppenderFactory<ILoggingEvent>> appenders) {
  96. this.appenders = ImmutableList.copyOf(appenders);
  97. }
  98. public void configure(MetricRegistry metricRegistry, String name) {
  99. LoggingUtil.hijackJDKLogging();
  100. CHANGE_LOGGER_CONTEXT_LOCK.lock();
  101. final Logger root;
  102. try {
  103. root = configureLoggers(name);
  104. } finally {
  105. CHANGE_LOGGER_CONTEXT_LOCK.unlock();
  106. }
  107. final LevelFilterFactory<ILoggingEvent> levelFilterFactory = new ThresholdLevelFilterFactory();
  108. final AsyncAppenderFactory<ILoggingEvent> asyncAppenderFactory = new AsyncLoggingEventAppenderFactory();
  109. final LayoutFactory<ILoggingEvent> layoutFactory = new DropwizardLayoutFactory();
  110. for (AppenderFactory<ILoggingEvent> output : appenders) {
  111. root.addAppender(output.build(loggerContext, name, layoutFactory, levelFilterFactory, asyncAppenderFactory));
  112. }
  113. StatusPrinter.setPrintStream(configurationErrorsStream);
  114. try {
  115. StatusPrinter.printIfErrorsOccured(loggerContext);
  116. } finally {
  117. StatusPrinter.setPrintStream(System.out);
  118. }
  119. final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
  120. MBEAN_REGISTRATION_LOCK.lock();
  121. try {
  122. final ObjectName objectName = new ObjectName("io.dropwizard:type=Logging");
  123. if (!server.isRegistered(objectName)) {
  124. server.registerMBean(new JMXConfigurator(loggerContext,
  125. server,
  126. objectName),
  127. objectName);
  128. }
  129. } catch (MalformedObjectNameException | InstanceAlreadyExistsException |
  130. NotCompliantMBeanException | MBeanRegistrationException e) {
  131. throw new RuntimeException(e);
  132. } finally {
  133. MBEAN_REGISTRATION_LOCK.unlock();
  134. }
  135. configureInstrumentation(root, metricRegistry);
  136. }
  137. public void stop() {
  138. // Should acquire the lock to avoid concurrent listener changes
  139. CHANGE_LOGGER_CONTEXT_LOCK.lock();
  140. try {
  141. loggerContext.stop();
  142. } finally {
  143. CHANGE_LOGGER_CONTEXT_LOCK.unlock();
  144. }
  145. }
  146. private void configureInstrumentation(Logger root, MetricRegistry metricRegistry) {
  147. final InstrumentedAppender appender = new InstrumentedAppender(metricRegistry);
  148. appender.setContext(loggerContext);
  149. appender.start();
  150. root.addAppender(appender);
  151. }
  152. private Logger configureLoggers(String name) {
  153. final Logger root = loggerContext.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
  154. loggerContext.reset();
  155. final LevelChangePropagator propagator = new LevelChangePropagator();
  156. propagator.setContext(loggerContext);
  157. propagator.setResetJUL(true);
  158. loggerContext.addListener(propagator);
  159. root.setLevel(level);
  160. final LevelFilterFactory<ILoggingEvent> levelFilterFactory = new ThresholdLevelFilterFactory();
  161. final AsyncAppenderFactory<ILoggingEvent> asyncAppenderFactory = new AsyncLoggingEventAppenderFactory();
  162. final LayoutFactory<ILoggingEvent> layoutFactory = new DropwizardLayoutFactory();
  163. for (Map.Entry<String, JsonNode> entry : loggers.entrySet()) {
  164. final Logger logger = loggerContext.getLogger(entry.getKey());
  165. final JsonNode jsonNode = entry.getValue();
  166. if (jsonNode.isTextual()) {
  167. // Just a level as a string
  168. logger.setLevel(Level.valueOf(jsonNode.asText()));
  169. } else if (jsonNode.isObject()) {
  170. // A level and an appender
  171. final LoggerConfiguration configuration;
  172. try {
  173. configuration = Jackson.newObjectMapper().treeToValue(jsonNode, LoggerConfiguration.class);
  174. } catch (JsonProcessingException e) {
  175. throw new IllegalArgumentException("Wrong format of logger '" + entry.getKey() + "'", e);
  176. }
  177. logger.setLevel(configuration.getLevel());
  178. logger.setAdditive(configuration.isAdditive());
  179. for (AppenderFactory<ILoggingEvent> appender : configuration.getAppenders()) {
  180. logger.addAppender(appender.build(loggerContext, name, layoutFactory, levelFilterFactory, asyncAppenderFactory));
  181. }
  182. } else {
  183. throw new IllegalArgumentException("Unsupported format of logger '" + entry.getKey() + "'");
  184. }
  185. }
  186. return root;
  187. }
  188. @Override
  189. public String toString() {
  190. return MoreObjects.toStringHelper(this)
  191. .add("level", level)
  192. .add("loggers", loggers)
  193. .add("appenders", appenders)
  194. .toString();
  195. }
  196. }