【问题标题】:Log exceptions in separate files for each tenant in multi-tenancy architecture在多租户架构中为每个租户在单独的文件中记录异常
【发布时间】:2014-03-10 10:59:20
【问题描述】:

我有一个支持多租户的应用程序,即一台服务器和多个数据库,每个租户都有单独的数据库。应用程序中抛出的所有异常都将记录在一个日志中。租户 ID 将与异常一起打印。

我想在单独的文件中处理它,即为每个租户一个单独的日志文件。这将有助于确定此异常是由属于特定租户的用户执行的活动引起的。是否有可能使用自定义ObjectRenderer 或任何其他技术来实现这一目标。提前致谢。

【问题讨论】:

    标签: java log4j tomcat7 multi-tenant


    【解决方案1】:

    我的建议是创建自己的Appenders。在自定义Appenders 中,您可以做任何您想做的事情,例如单独的日志文件等,

    参考: How to create a own Appender in log4j? http://logging.apache.org/log4j/2.x/manual/extending.html

    【讨论】:

      【解决方案2】:

      我建议您将 logback 与 MDC 一起使用。

      查看文档

      我使用的是请求响应过滤器,在请求过滤器中,我会将 tenantId 添加到 MDC 上下文中,从请求对象中读取值,然后在响应过滤器中将其从 MDC 中删除。

      并且在logback配置中,配置文件名为,

      <file>${FILE_PATH}/${tenantId}.log</file>
      

      将鉴别器指定为,

      <discriminator>
          <key>tenantId</key>
          <defaultValue>defaultFileName</defaultValue>
      </discriminator>
      

      这里 logback 将 tenantId 视为鉴别器并从 MDC 上下文中获取它,如果它不可用,则将其设置为默认值。

      下面是我们正在使用的完整配置,

      <property name="USER_HOME" value="/home/logs" />
      
      <appender name="FILE-THREAD" class="ch.qos.logback.classic.sift.SiftingAppender">
      
          <!-- This is MDC value -->
          <!-- This is being set via request response filter via Java code -->
          <discriminator>
              <key>tenantId</key>
              <defaultValue>applyService</defaultValue>
          </discriminator>
      
          <sift>
      
              <!-- A standard RollingFileAppender, the log file is based on 'logFileName' at runtime  -->
              <appender name="FILE-${tenantId}"
                        class="ch.qos.logback.core.rolling.RollingFileAppender">
                  <file>${USER_HOME}/${tenant}.log</file>
      
                  <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                      <Pattern>
                          %d{yyyy-MM-dd HH:mm:ss} [%level] [%logger:%line] [%mdc{tenant}] [%mdc{username}] - %msg%n
                      </Pattern>
                  </encoder>
      
                  <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
                      <!-- rollover daily -->
                      <fileNamePattern>${USER_HOME}/${tenant}-%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern>
                      <!-- each file should be at most 10MB, keep 60 days worth of history-->
                      <maxFileSize>10MB</maxFileSize>
                      <maxHistory>60</maxHistory>
                  </rollingPolicy>
      
              </appender>
      
          </sift>
      </appender>
      
      <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
          <layout class="ch.qos.logback.classic.PatternLayout">
              <Pattern>
                  %d{yyyy-MM-dd HH:mm:ss} [%level] [%logger:%line] [%mdc{tenant}] [%mdc{username}] - %msg%n
              </Pattern>
          </layout>
      </appender>
      
      <logger name="com.test.client" level="debug" additivity="false">
          <appender-ref ref="FILE-THREAD" />
      </logger>
      
      <root level="INFO">
          <appender-ref ref="STDOUT" />
      </root>
      

      Java 代码:

         @Provider
      public class RequestandResponseFilter implements ContainerRequestFilter, ContainerResponseFilter {
          
          @Override
          public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
                  throws IOException {
              
              MDC.remove( "tenantId" );
      
          }
      
          @Override
          public void filter(ContainerRequestContext requestContext) throws IOException {
               String reqJsonStr = EMPTY_STRING;
               
               try (BufferedReader buffer = new BufferedReader(new InputStreamReader( requestContext.getEntityStream() ))) {
                   reqJsonStr = buffer.lines().collect(Collectors.joining("\n"));
                  }
               if( reqJsonStr != null && !reqJsonStr.isEmpty() ) {
                   JsonObject reqJson = //convertStringtoJson
                   MDC.put("tenantId", reqJson.get("tenantId"));
               }
               
          }
          
      }
      

      【讨论】:

      • 你能分享你设置 mdc 上下文的 java 代码吗?
      猜你喜欢
      • 1970-01-01
      • 2011-06-01
      • 2023-03-10
      • 2021-05-14
      • 2015-01-05
      • 2012-03-24
      • 2020-11-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多