Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,15 +16,21 @@

package org.springframework.boot.logging.logback;

import java.lang.management.ManagementFactory;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.management.MBeanServer;
import javax.management.ObjectName;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.jmx.JMXConfigurator;
import ch.qos.logback.classic.jmx.MBeanUtil;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.classic.jul.LevelChangePropagator;
import ch.qos.logback.classic.turbo.TurboFilter;
Expand Down Expand Up @@ -56,6 +62,7 @@
* @author Dave Syer
* @author Andy Wilkinson
* @author Ben Hale
* @author Vedran Pavic
*/
public class LogbackLoggingSystem extends Slf4JLoggingSystem {

Expand Down Expand Up @@ -126,6 +133,7 @@ protected void loadDefaults(LoggingInitializationContext initializationContext,
LogFile logFile) {
LoggerContext context = getLoggerContext();
stopAndReset(context);
registerJmxConfigurator(context, initializationContext, null, logFile);
LogbackConfigurator configurator = new LogbackConfigurator(context);
Environment environment = initializationContext.getEnvironment();
context.putProperty(LoggingSystemProperties.LOG_LEVEL_PATTERN,
Expand All @@ -145,6 +153,7 @@ protected void loadConfiguration(LoggingInitializationContext initializationCont
super.loadConfiguration(initializationContext, location, logFile);
LoggerContext loggerContext = getLoggerContext();
stopAndReset(loggerContext);
registerJmxConfigurator(loggerContext, initializationContext, location, logFile);
try {
configureByResourceUrl(initializationContext, loggerContext,
ResourceUtils.getURL(location));
Expand Down Expand Up @@ -196,6 +205,28 @@ private void addLevelChangePropagator(LoggerContext loggerContext) {
loggerContext.addListener(levelChangePropagator);
}

private void registerJmxConfigurator(LoggerContext loggerContext,
LoggingInitializationContext initializationContext, String configLocation,
LogFile logFile) {
String objectNameAsStr = MBeanUtil.getObjectNameFor(loggerContext.getName(),
JMXConfigurator.class);
ObjectName objectName = MBeanUtil.string2ObjectName(loggerContext, this,
objectNameAsStr);
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
if (!MBeanUtil.isRegistered(server, objectName)) {
LoggingSystemJMXConfigurator jmxConfigurator = new LoggingSystemJMXConfigurator(
loggerContext, server, objectName, initializationContext,
configLocation, logFile);
try {
server.registerMBean(jmxConfigurator, objectName);
}
catch (Exception e) {
getLogger(LogbackLoggingSystem.class.getName())
.error("Failed to create mbean", e);
}
}
}

@Override
public void cleanUp() {
LoggerContext context = getLoggerContext();
Expand Down Expand Up @@ -317,4 +348,33 @@ public void run() {

}

private class LoggingSystemJMXConfigurator extends JMXConfigurator {

private LoggingInitializationContext initializationContext;

private String configLocation;

private LogFile logFile;

LoggingSystemJMXConfigurator(LoggerContext loggerContext, MBeanServer server,
ObjectName objectName, LoggingInitializationContext initializationContext,
String configLocation, LogFile logFile) {
super(loggerContext, server, objectName);
this.initializationContext = initializationContext;
this.configLocation = configLocation;
this.logFile = logFile;
}

@Override
public void reloadDefaultConfiguration() {
initialize(this.initializationContext, this.configLocation, this.logFile);
}

@Override
public void reloadByFileName(String fileName) {
initialize(this.initializationContext, fileName, this.logFile);
}

}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -18,11 +18,14 @@

import java.io.File;
import java.io.FileReader;
import java.lang.management.ManagementFactory;
import java.util.EnumSet;
import java.util.List;
import java.util.logging.Handler;
import java.util.logging.LogManager;

import javax.management.ObjectName;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
Expand Down Expand Up @@ -487,6 +490,43 @@ public void testDateformatPatternProperty() {
.containsPattern("\\d{4}-\\d{2}\\-\\d{2}T\\d{2}:\\d{2}:\\d{2}");
}

@Test
public void testDefaultJmxConfigurator() throws Exception {
this.loggingSystem.beforeInitialize();
assertThat(ManagementFactory.getPlatformMBeanServer().queryMBeans(
new ObjectName("ch.qos.logback.classic:Name=default,*"), null))
.hasSize(1);
}

@Test
public void testExplicitJmxConfigurator() throws Exception {
this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(this.initializationContext,
"classpath:logback-jmxconfigurator.xml", null);
assertThat(ManagementFactory.getPlatformMBeanServer().queryMBeans(
new ObjectName("ch.qos.logback.classic:Name=default,*"), null))
.hasSize(1);
}

@Test
public void testShutdownUnregistersJmxConfigurator() throws Exception {
this.loggingSystem.beforeInitialize();
this.loggingSystem.getShutdownHandler().run();
assertThat(ManagementFactory.getPlatformMBeanServer().queryMBeans(
new ObjectName("ch.qos.logback.classic:Name=default,*"), null)).isEmpty();
}

@Test
public void testTwoLoggingSystemsYieldSingleJmxConfigurator() throws Exception {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't consider this to be a good thing actually. Which logging configuration are you effectively managing with such setup? Is there a way to provide another name than default so that we get one MBean per app instead?

this.loggingSystem.beforeInitialize();
LogbackLoggingSystem anotherLoggingSystem = new LogbackLoggingSystem(
getClass().getClassLoader());
anotherLoggingSystem.beforeInitialize();
assertThat(ManagementFactory.getPlatformMBeanServer().queryMBeans(
new ObjectName("ch.qos.logback.classic:Name=default,*"), null))
.hasSize(1);
}

private static Logger getRootLogger() {
ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory();
LoggerContext context = (LoggerContext) factory;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
<jmxConfigurator/>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd put this one first so that it is more explicit

</configuration>