【问题标题】:How to Override request logging mechanism in Jetty 11.0.6如何在 Jetty 11.0.6 中覆盖请求日志记录机制
【发布时间】:2021-08-11 06:48:36
【问题描述】:

我正在将 jetty 9 更新为 jetty11,我看到 org.eclipse.jetty.server.AsyncNCSARequestLog 已被弃用,并为此引入了另外两个类 - org.eclipse.jetty.server.CustomRequestLog 和 org.eclipse。 jetty.server.AsyncRequestLogWriter.

但问题是我曾经扩展 AsyncNCSARequestLog 类并覆盖日志和写入方法(有关更多信息,请参见下面的代码)但在 Jetty11 中找不到方法。

public class JettyRequestLogger extends AsyncNCSARequestLog
    {
        private Request request;
    
        @Override
        public void log(Request request, Response response)
        {
            this.request = request;
            super.log(request, response);
        }
    
        @Override
        public void write(String logStr) throws IOException
        {
            logStr = setCustomAttributesToLog(logStr);
            super.write(logStr);
        }
       private String setCustomAttributesToLog(String logStr)
       {
         // logic here
       }

    }

更新: 我的用例是在打印码头日志时添加自定义属性,如 UserId、UserName 和自定义属性等

【问题讨论】:

  • 你看过CustomRequestLog能做什么吗?很有可能它已经涵盖了您的用例,并且您不再需要自定义代码。如果您有 CustomRequestLog 尚未涵盖的新用例,Eclipse Jetty 开发人员想知道以便他们添加它!
  • @JoakimErdfelt 我的用例非常简单。只需要在编写日志时添加额外的属性,如用户 ID、用户名等。
  • CustomRequestLog 格式字符串 %{d}u 可能就是您要找的。​​span>
  • @JoakimErdfelt 我编写了一个自定义类“MyJettyLogger.java”,它扩展了“org.eclipse.jetty.server.CustomRequestLog”。那么,我们需要在哪里定义这个类呢?所以,Jetty 可以识别这个而不是 CustomRequestLog 类。

标签: java eclipse jetty slf4j


【解决方案1】:

自 Jetty 9.x 以来,RequestLog 整体发生了一些重要变化

RequestLog 实现现在已添加到Server,不要使用老式的RequestLogHandler

// Modern version (for all system loads and speeds)
Slf4jRequestLogWriter slfjRequestLogWriter = new Slf4jRequestLogWriter();
slfjRequestLogWriter.setLoggerName("com.company.request.log");
String format = "%{client}a - %u %t '%r' %s %O '%{Referer}i' '%{User-Agent}i' '%C'";
CustomRequestLog customRequestLog = new CustomRequestLog(slfjRequestLogWriter, format);
server.setRequestLog(customRequestLog);
// Old school version (not for busy systems)
Path outputPattern = logsDir.resolve("yyyy_mm_dd.request.log");
AsyncRequestLogWriter logWriter = new AsyncRequestLogWriter(outputPattern.toString());
logWriter.setFilenameDateFormat("yyyy_MM_dd");
logWriter.setRetainDays(90);
logWriter.setTimeZone("GMT");
String format = "%{client}a - %u %t '%r' %s %O '%{Referer}i' '%{User-Agent}i' '%C'";
CustomRequestLog requestLog = new CustomRequestLog(logWriter, format);
server.setRequestLog(requestLog);

虽然RequestLogHandler 仍然存在,但它有一些基本缺陷,即它不会记录在解析步骤期间失败的请求,或在合规性验证步骤期间失败的请求,或在 ssl/tls 验证步骤期间失败的请求,或不属于已知上下文的请求,或在响应生成期间失败的交换,或通过错误处理层返回应用程序但在应用程序层失败的交换等。如您所见,有很多边缘情况RequestLogHandler 无法处理,所以创建了基础Server.setRequestLog(RequestLog),使用它。

RequestResponse 的内部更改已在每个组件“提交”时保持这些组件的状态,因此您必须使用 RequestResponse 中的这些新方法来在网络层实际处理这些对象时,获取有关这些对象状态的准确信息。由于 when 在 http 交换和生命周期期间发生日志记录,使用原始方法很容易导致错误/不准确的数据。

RequestLog Jetty 的实现由两部分组成。

RequestLog 本身是一个接受RequestResponse 并将信息格式化为日志行字符串的组件。

RequestLog 使用RequestLog.Writer 组件将原始字符串写入任何必要的内容。

  • Slf4jRequestLogWriter(默认实现,推荐)- 将字符串写入名为 logger 的 slf4j。这是设置唯一日志文件、滚动行为(按大小、日期、任意持续时间或其他触发器)、旧日志归档(带压缩)、警报、支持扩展访问日志分析工具等的最佳选择.
  • RequestLogWriter(老派,很多陷阱)- 同步写入任意任意OutputStream(您可以在此处使用 Jetty 的老派RolloverFileOutputStream)。这将在收到每个条目后写入,如果您的网络事件超过磁盘 I/O 可以处理的数量(一个令人惊讶的常见情况),请切换到使用异步版本突发写入。
  • AsyncRequestLogWriter - RequestLogWriter 的异步版本,如果您的磁盘 I/O 仍然无法处理更多的网络事件,请切换到 Slf4jRequestLogWriter 并使用各种 slf4j 实现的高级异步日志附加,这比比 Jetty 本身在 AsyncRequestLogWriter 中使用的简单 java.io 行为。

自定义请求日志的最常见形式是更改记录的内容,而不是自定义输出格式(已由CustomRequestLog 本身处理)。

一个例子是只记录错误情况,而不记录其余情况。

请注意,这显示了上述“已提交”状态信息的示例。

package jetty;

import org.eclipse.jetty.server.CustomRequestLog;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;

public class ErrorOnlyRequestLog extends CustomRequestLog
{
    public ErrorOnlyRequestLog(Writer writer, String formatString)
    {
        super(writer, formatString);
    }

    public ErrorOnlyRequestLog(String file)
    {
        super(file);
    }

    public ErrorOnlyRequestLog(String file, String format)
    {
        super(file, format);
    }

    @Override
    public void log(Request request, Response response)
    {
        // Get the response status actually sent (as you cannot rely on
        // the Response.getStatus() at this point in time, which can change
        // due to a number of factors, including error handling, dispatch
        // completion, recycling, etc)
        int committedStatus = response.getCommittedMetaData().getStatus();

        // only interested in error cases - bad request & server errors
        if ((committedStatus >= 500) || (committedStatus == 400))
        {
            super.log(request, response);
        }
        else
        {
            System.err.println("### Ignored request (response.committed.status=" + committedStatus + "): " + request);
        }
    }
}

【讨论】:

  • 你能解释更多吗 - 字符串格式 = "%{client}a - %u %t '%r' %s %O '%{Referer}i' '%{User-Agent }我知道了'”。我的用例是添加 userId、Username 等属性。每个字符的含义是什么?我们如何使用它?
  • CustomRequestLog 的 javadoc/apidoc 包含您正在寻找的详细信息。
猜你喜欢
  • 2017-03-17
  • 2022-01-13
  • 2014-03-17
  • 2012-01-12
  • 1970-01-01
  • 1970-01-01
  • 2016-04-27
  • 2022-01-27
  • 1970-01-01
相关资源
最近更新 更多