Tomcat WAR - 配置Logback以在路径中使用应用程序名称

Hax*_*lit 16 java tomcat logback slf4j

我在war文件lib文件夹中部署了logback,并且在classes文件夹中有以下logback.xml.

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
  <property name="destination" value="${catalina.base:-./temp}/logs/${appName:-myapp}" />

  <appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${destination}.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <!-- rollover daily -->
      <fileNamePattern>${destination}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
      <!-- Keep logs for 7 days -->
      <maxHistory>7</maxHistory>

      <timeBasedFileNamingAndTriggeringPolicy
            class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
        <!-- or whenever the file size reaches 100MB -->
        <maxFileSize>100MB</maxFileSize>
      </timeBasedFileNamingAndTriggeringPolicy>
    </rollingPolicy>
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>

  <root level="error">
    <appender-ref ref="ROLLING" />
  </root>
</configuration>
Run Code Online (Sandbox Code Playgroud)

在第3行,我有一些变量替换,为我的日志文件创建路径.

  <property name="destination" value="${catalina.base:-./temp}/logs/${appName:-myapp}" />
Run Code Online (Sandbox Code Playgroud)

我想让它如此${appName}评估已部署的war文件的当前名称.

因此,如果我的网络应用文件夹看起来像这样

webapps
 - myapp.war
 - myapp-dev.war
Run Code Online (Sandbox Code Playgroud)

${destination}myapp.war 的属性将评估为.../logs/myapp,myapp-dev.war将评估为.../logs/myapp-dev.是否有JNDI属性或我可以访问appName的东西?

我想避免手动重新配置记录器.

谢谢!

Mic*_*l-O 10

编辑2013-06:我Listener在Maven Central上将其作为OSS提供.查看项目主页.

是的,这是可行的.首先,你总是可以依赖,catalina.base因为没有它,Tomcat将无法运行.为了将上下文名称注入属性.编写一个上下文监听器,它将上下文名称放入JNDI上下文中,并在关闭时删除.完成后,您可以使用logback直接使用JNDI检索值.有直接的支持.在contextName元素中写下它,你就完成了.

我已经自己实现了它,它适用于我的所有项目.如果您或其他人感兴趣,我可以在星期一分享整个代码.

编辑,这是代码:

import org.apache.catalina.Context;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.deploy.ContextEnvironment;
import org.apache.commons.lang.StringUtils;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;

public class LogbackContextNameListener implements LifecycleListener {

    private static final Log logger = LogFactory
            .getLog(LogbackContextNameListener.class);
    private Context context;

    private String name = "logback/contextName";

    @Override
    public void lifecycleEvent(LifecycleEvent le) {

        if (le.getLifecycle() instanceof Context)
            context = (Context) le.getLifecycle();
        else
            return;

        if (le.getType().equals(Lifecycle.START_EVENT)) {
            ContextEnvironment ce = new ContextEnvironment();
            ce.setName(getName());
            ce.setOverride(false);
            ce.setType("java.lang.String");
            String value = StringUtils.remove(context.getServletContext()
                    .getContextPath(), '/');
            ce.setValue(value);
            logger.debug(String.format("Adding env entry '%s' with value '%s'",
                    getName(), value));
            context.getNamingResources().addEnvironment(ce);
        }

        if (le.getType().equals(Lifecycle.STOP_EVENT)) {
            logger.debug(String.format("Removing env entry '%s'", getName()));
            context.getNamingResources().removeEnvironment(name);
        }

    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        if (StringUtils.isEmpty(name))
            throw new IllegalArgumentException(
                    "Parameter 'name' cannot be empty");

        this.name = name;
    }

}
Run Code Online (Sandbox Code Playgroud)

合适的配置如下所示:

<configuration scan="true" scanPeriod="30 minutes">

    <insertFromJNDI env-entry-name="java:comp/env/logback/contextName" as="contextName" />
    <contextName>${contextName}</contextName>

    <appender name="FILE"
        class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${catalina.base}/logs/${CONTEXT_NAME}.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- daily rollover -->
            <fileNamePattern>${catalina.base}/logs/${CONTEXT_NAME}.log.%d.gz</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%-27(%d{HH:mm:ss.SSS} [%.-12thread]) %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="INFO"><!-- WARN -->
        <appender-ref ref="FILE" />
    </root>

</configuration>
Run Code Online (Sandbox Code Playgroud)

这在Tomcat 6中完美运行.我想,它将在没有更改的Tomcat 7上运行.

  • 你不需要依赖。它不属于您的应用程序,而是位于 tomcat/lib 中的单独 JAR 中。不,这不能从应用程序中完成。JDNI 上下文在应用程序内是只读的。 (2认同)

Cek*_*eki 5

这是建立在迈克尔-O 的回答之上的。考虑到catalina.base在 Tomcat 下运行时 始终是已定义的系统属性,我们只需担心定义appName. Logback 支持从 JNDI 检索变量。如果 appName 在 JNDI 中定义,您的配置文件将变为:

<configuration>
  <!-- retrieve appName from JNDI to set the variable appName -->
  <insertFromJNDI env-entry-name="java:comp/env/appName" as="appName" />
  <!-- let the context name be the applicaiton name -->
  <contextName>${appName}</contextName>

  <property name="destination" 
            value="${catalina.base:-./temp}/logs/${CONTEXT_NAME:-myapp}" />

  <appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${destination}.log</file>
    ... remainder of config file omitted for brevity  
  </appender>
</configuration>
Run Code Online (Sandbox Code Playgroud)

我想提一下,您也可以直接在 logback.xml 中定义 appName,而不是在 JNDI 中。(毕竟,logback.xml 文件随您的网络应用程序一起提供,其名称已确定。但是,您的问题明确排除了这一假设。)因此,您的 logback.xml 文件可以简化为:

<configuration>
  <contextName>the_name_of_your_webapp</contextName>
  <property name="destination" 
            value="${catalina.base:-./temp}/logs/${CONTEXT_NAME:-myapp}" />
   ... the rest omitted for brevity
</configuration? 
Run Code Online (Sandbox Code Playgroud)

顺便说一句,一旦您找到满意的解决方案,请毫不犹豫地通过在 logback-user 列表上发布来分享。