在Spring Boot 1.5+中,可以通过http端点来更改日志级别。
添加
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
然后你可以使用
curl -X "POST" "http://localhost:8080/loggers/de.springbootbuch" \
-H "Content-Type: application/json; charset=utf-8" \
-d $'{
"configuredLevel": "WARN"
}'
除了 /loggers/ 以外的所有内容都是记录器的名称。
如果您在 PCF 中运行此操作,它会变得更好:这直接受到其后端支持。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
其次,您需要按照Dennis在评论中所说的方式公开端点(loggers
默认情况下被禁用):
management.endpoints.web.exposure.include=health,info,loggers
curl -X "GET" "http://localhost:8080/actuator/loggers"
要设置Root
日志级别,您可以使用
curl -X "POST" "http://localhost:8080/actuator/loggers/ROOT" -H "Content-Type: application/json; charset=utf-8" -d $'{ "configuredLevel": "INFO" }'
management.endpoints.web.exposure.include=...,loggers
属性是缺失的一部分! - t0r0X这是 @Michael Simons 答案的扩展。使用此方法,您将拥有用于执行此操作的用户界面:
这种方法可能会多一些步骤,但可以解决更多问题。我们将使用一个名为Spring Boot Admin Server的工具。
首先,您需要包含一些依赖项
<!--Dependency for registering your app as a Spring Boot Admin Server-->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server</artifactId>
<version>1.3.3</version>
</dependency>
<!--Provide a nice looking ui-->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server-ui</artifactId>
<version>1.3.3</version>
</dependency>
<!--Dependency for registering your app as a Spring Boot Admin Client-->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>org.jolokia</groupId>
<artifactId>jolokia-core</artifactId>
</dependency>
使用注解@EnableAdminServer
,使您的应用成为Spring Boot Admin Server。
@SpringBootApplication
@EnableAdminServer
public class Application {
public static void main(String[] args) {
// ... your code as before ...
}
}
在你的application.properties
文件中添加以下内容:
将你的应用程序注册到Spring Boot Admin Server中,这仍然是你的应用程序
spring.boot.admin.url=http://localhost:8031
指导Spring Boot Admin Server在哪里找到客户端
// For versions 2.*.*
spring.boot.admin.client.url=http://localhost:8031
// For versions 1.*.*
spring.boot.admin.client.service-url=http://localhost:8031
spring.boot.admin.client.management-url=http://localhost:8031
spring.boot.admin.client.health-url=http://localhost:8031/health
在你的logback.xml
中只需添加以下行:<jmxConfigurator/>
。这将通过JMX配置logback。更多信息在此处
... 然后voila,完成了。现在您可以在运行时更改任何记录器的调试级别。
i. 只需访问Spring Boot Admin服务器的网址-在我们这里(http:/localhost:8031
)。
ii. 在主页上将显示已注册的应用程序(客户端)列表。
iii. 单击“详细信息”以针对已注册的客户端进入另一个页面。
iv. 单击“日志记录”选项卡,其中将列出应用程序中注册的所有记录器。
v. 您可以更改日志级别,它将在运行时更改您的日志记录级别。这是您期望的一部分代码片段
如果您在项目中使用logback
api配置日志记录,则可以使用logback
api的自动扫描功能。
根据文档:
logback-classic
会扫描其配置文件中的更改,并在配置文件更改时自动重新配置自身。 为了指示logback-classic
扫描其配置文件中的更改并自动重新配置自身,请将<configuration>
元素的scan属性设置为true。
<configuration scan="true">
...
</configuration>
扫描频率: "默认情况下,配置文件将每分钟扫描一次以检测更改
"。有关更多详细信息,请参阅logback
的API文档。
@PostMapping("/changeloglevel")
public void changeloglevel(@RequestParam String loglevel)
{
LoggerContext loggerContext = (LoggerContext)LoggerFactory.getILoggerFactory();
loggerContext.getLogger("package where springboot main class resides").setLevel(Level.toLevel(loglevel));
}
日志级别可以是ERROR(错误)、INFO(信息)、WARN(警告)等。
loggerContext.getLogger(Logger.ROOT_LOGGER_NAME).setLevel(Level.valueOf(loglevel));
。 - Ahmed Nabil默认的日志记录提供程序是logback。要设置系统,以便在运行时可以更改日志记录级别,您需要执行以下步骤:
首先,在src/main/resources
中创建一个自定义的logback配置,命名为logback-spring.xml
,其中包括spring的默认配置器,然后添加指令,通过JMX公开logback配置:
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<jmxConfigurator />
</configuration>
org.jolokia:jolokia-core
。/jolokia
端点。该协议在此处有文档说明,但并不易读。以下是一些您可以直接从浏览器访问的GET
示例:/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/getLoggerLevel/ROOT
将ROOT记录器级别更改为调试:
/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/setLoggerLevel/ROOT/debug
spring-boot-actuator意识到/jolokia
端点,并将其标记为sensitive=true
,因此如果在类路径上有spring-security,则需要进行身份验证。
有三种方法可以做到这一点。
请查看 Amy DeGregorio 的 this 博客以获取更多详细信息。
对于IntelliJ用户:我有一个类似的情况,最终编写了自己的Intellij插件,这对我来说是最简单的解决方案。它本质上是actuator日志端点的包装器。
在此处查看:https://plugins.jetbrains.com/plugin/17101-logboot LogBoot插件
https://gist.github.com/iamkristian/943918/043ac51bd80321a0873d93277979c8a9a20a9a48#file-log4jadmin-jsp
<%@ page language="java" contentType="text/html;charset=UTF-8" %>
<%@ page import="org.apache.log4j.Level" %>
<%@ page import="org.apache.log4j.LogManager" %>
<%@ page import="org.apache.log4j.Logger" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="java.util.Enumeration" %>
<%@ page import="java.util.Set" %>
<%@ page import="java.util.Arrays" %>
<% long beginPageLoadTime = System.currentTimeMillis();%>
<html>
<head>
<title>Log4J Administration</title>
<style type="text/css">
<!--
#content {
margin: 0px;
padding: 0px;
text-align: center;
background-color: #ccc;
border: 1px solid #000;
width: 100%;
}
body {
position: relative;
margin: 10px;
padding: 0px;
color: #333;
}
h1 {
margin-top: 20px;
font: 1.5em Verdana, Arial, Helvetica sans-serif;
}
h2 {
margin-top: 10px;
font: 0.75em Verdana, Arial, Helvetica sans-serif;
text-align: left;
}
a, a:link, a:visited, a:active {
color: red;
text-decoration: none;
text-transform: uppercase;
}
table {
width: 100%;
background-color: #000;
padding: 3px;
border: 0px;
}
th {
font-size: 0.75em;
background-color: #ccc;
color: #000;
padding-left: 5px;
text-align: center;
border: 1px solid #ccc;
white-space: nowrap;
}
td {
font-size: 0.75em;
background-color: #fff;
white-space: nowrap;
}
td.center {
font-size: 0.75em;
background-color: #fff;
text-align: center;
white-space: nowrap;
}
.filterForm {
font-size: 0.9em;
background-color: #000;
color: #fff;
padding-left: 5px;
text-align: left;
border: 1px solid #000;
white-space: nowrap;
}
.filterText {
font-size: 0.75em;
background-color: #fff;
color: #000;
text-align: left;
border: 1px solid #ccc;
white-space: nowrap;
}
.filterButton {
font-size: 0.75em;
background-color: #000;
color: #fff;
padding-left: 5px;
padding-right: 5px;
text-align: center;
border: 1px solid #ccc;
width: 100px;
white-space: nowrap;
}
-->
</style>
</head>
<body onLoad="javascript:document.logFilterForm.logNameFilter.focus();">
<%
String containsFilter = "Contains";
String beginsWithFilter = "Begins With";
String[] logLevels = {"debug", "info", "warn", "error", "fatal", "off"};
String targetOperation = (String) request.getParameter("operation");
String targetLogger = (String) request.getParameter("logger");
String targetLogLevel = (String) request.getParameter("newLogLevel");
String logNameFilter = (String) request.getParameter("logNameFilter");
String logNameFilterType = (String) request.getParameter("logNameFilterType");
%>
<div id="content">
<h1>Log4J Administration</h1>
<div class="filterForm">
<form action="log4jAdmin.jsp" name="logFilterForm">Filter Loggers:
<input name="logNameFilter" type="text" size="50" value="<%=(logNameFilter == null ? "":logNameFilter)%>"
class="filterText"/>
<input name="logNameFilterType" type="submit" value="<%=beginsWithFilter%>" class="filterButton"/>
<input name="logNameFilterType" type="submit" value="<%=containsFilter%>" class="filterButton"/>
<input name="logNameClear" type="button" value="Clear" class="filterButton"
onmousedown='javascript:document.logFilterForm.logNameFilter.value="";'/>
<input name="logNameReset" type="reset" value="Reset" class="filterButton"/>
<param name="operation" value="changeLogLevel"/>
</form>
</div>
<table cellspacing="1">
<tr>
<th width="25%">Logger</th>
<th width="25%">Parent Logger</th>
<th width="15%">Effective Level</th>
<th width="35%">Change Log Level To</th>
</tr>
<%
Enumeration loggers = LogManager.getCurrentLoggers();
HashMap loggersMap = new HashMap(128);
Logger rootLogger = LogManager.getRootLogger();
if (!loggersMap.containsKey(rootLogger.getName())) {
loggersMap.put(rootLogger.getName(), rootLogger);
}
while (loggers.hasMoreElements()) {
Logger logger = (Logger) loggers.nextElement();
if (logNameFilter == null || logNameFilter.trim().length() == 0) {
loggersMap.put(logger.getName(), logger);
} else if (containsFilter.equals(logNameFilterType)) {
if (logger.getName().toUpperCase().indexOf(logNameFilter.toUpperCase()) >= 0) {
loggersMap.put(logger.getName(), logger);
}
} else {
// Either was no filter in IF, contains filter in ELSE IF, or begins with in ELSE
if (logger.getName().startsWith(logNameFilter)) {
loggersMap.put(logger.getName(), logger);
}
}
}
Set loggerKeys = loggersMap.keySet();
String[] keys = new String[loggerKeys.size()];
keys = (String[]) loggerKeys.toArray(keys);
Arrays.sort(keys, String.CASE_INSENSITIVE_ORDER);
for (int i = 0; i < keys.length; i++) {
Logger logger = (Logger) loggersMap.get(keys[i]);
// MUST CHANGE THE LOG LEVEL ON LOGGER BEFORE GENERATING THE LINKS AND THE
// CURRENT LOG LEVEL OR DISABLED LINK WON'T MATCH THE NEWLY CHANGED VALUES
if ("changeLogLevel".equals(targetOperation) && targetLogger.equals(logger.getName())) {
Logger selectedLogger = (Logger) loggersMap.get(targetLogger);
selectedLogger.setLevel(Level.toLevel(targetLogLevel));
}
String loggerName = null;
String loggerEffectiveLevel = null;
String loggerParent = null;
if (logger != null) {
loggerName = logger.getName();
loggerEffectiveLevel = String.valueOf(logger.getEffectiveLevel());
loggerParent = (logger.getParent() == null ? null : logger.getParent().getName());
}
%>
<tr>
<td><%=loggerName%>
</td>
<td><%=loggerParent%>
</td>
<td><%=loggerEffectiveLevel%>
</td>
<td class="center">
<%
for (int cnt = 0; cnt < logLevels.length; cnt++) {
String url = "log4jAdmin.jsp?operation=changeLogLevel&logger=" + loggerName + "&newLogLevel=" + logLevels[cnt] + "&logNameFilter=" + (logNameFilter != null ? logNameFilter : "") + "&logNameFilterType=" + (logNameFilterType != null ? logNameFilterType : "");
if (logger.getLevel() == Level.toLevel(logLevels[cnt]) || logger.getEffectiveLevel() == Level.toLevel(logLevels[cnt])) {
%>
[<%=logLevels[cnt].toUpperCase()%>]
<%
} else {
%>
<a href='<%=url%>'>[<%=logLevels[cnt]%>]</a>
<%
}
}
%>
</td>
</tr>
<%
}
%>
</table>
<h2>
Revision: 1.0<br/>
Page Load Time (Millis): <%=(System.currentTimeMillis() - beginPageLoadTime)%>
</h2>
</div>
</body>
</html>
application.properties
文件中添加management.endpoints.web.exposure.include
设置,并将其值设置为loggers。如果你的application.properties
文件中没有这行设置,那么就加上:management.endpoints.web.exposure.include=health,info,loggers
。因为它的默认值只包括health和info。 - Dennis