我有一个提供Web请求的spring应用程序。每个请求方法都如下所示
@RequestMapping(value = someUri, method = RequestMethod.POST)
Response someUriProcessor (SomeRequestModelMethod request) throws Exception {
try (JsonLogger logger = new JsonLogger(request, loggingTest1Uri)){
// get actual result
Response result = getSomeResultMethod(request);
// feed result to special logging object
logger.setResult (result);
// return result to client
return result;
}
}
JsonLogger类以close方法生成JSON对象,并通过标准的slf4j日志框架登录,并将其上传到日志分析工具(Splunk),记录请求,响应,响应时间等。
在执行getSomeResultMethod期间执行大量工作,使用标准的slf4j生成许多有用的日志,并在生产中使用logback绑定。 我希望这些日志包含在JsonLogger中而不涉及所有底层类(有很多它们),比如使用方法JsonLogger.appendToResultLog(String txt)。我的第一个想法是创建我自己的包装slf4j绑定,在每次调用logger.info,logger.error等方法时展开stacktrace,使用反射到rest控制器方法并在其中附加日志字符串JsonLogger。
我有强烈的感觉,我正在发明一辆自行车。是否有任何或多或少的标准方法来实现所需的结果?
答案 0 :(得分:1)
完成没有方面和反思 - 只是自定义logback appender。
public class JsonInnerLogsAppender extends AppenderBase<ILoggingEvent> {
public JsonInnerLogsAppender () {
this.setName("JSON_LOGGING_INTERNAL");
}
@Override
protected void append(ILoggingEvent eventObject) {
JsonLogger.putLogInfo(eventObject.getFormattedMessage());
}
}
和JsonLogger一样
public class JsonLogger implements AutoCloseable {
/**
* Contains mapping between current thread id and corresponding JsonLogger object
*/
private static transient ConcurrentHashMap<Long, JsonLogger> loggersMap = new ConcurrentHashMap<>();
/**
* Should be configured with special appender pattern, like
* <encoder>
* <pattern>%date{ISO8601} [%-18thread] %-5level %msg %logger{70}%n</pattern>
* </encoder>
*/
private transient Logger logger = LoggerFactory.getLogger(getClass());
private transient static Gson gson = new Gson();
/**
* Container that would be serialized to JSON after close and added to JSON log
*/
private final JsonLogContainer logContainer;
public JsonLogger (Object request, HttpServletRequest servletRequest) {
this.logContainer = new JsonLogContainer(gson.toJson(request), servletRequest.getRequestURI());
// request is started
loggersMap.put(Thread.currentThread().getId(), this);
}
/**
* @param logString formatted log string, called from custom appender
*/
public static void putLogInfo (String logString) {
// find appropriate JsonLogger instance (if any) and append log to it
JsonLogger jsonLogger = loggersMap.get(Thread.currentThread().getId());
if ( null != jsonLogger ) {
jsonLogger.putLogToContainer(logString);
}
}
private void putLogToContainer (String logString) {
logContainer.putLog(logString);
}
@Override
public void close() throws Exception {
String log = this.logContainer.getLog(new Date());
// request is completed
loggersMap.remove(Thread.currentThread().getId());
// put record to JSON log
logger.info(log);
}
public void setResult(Object result) {
logContainer.setResponse(gson.toJson(result));
}
}
答案 1 :(得分:0)
确实有一些更简单的选择。我认为spring最干净的方法是创建一个自定义Interceptor(它非常像servlet过滤器,但具有更精细的功能)。
您可以在Spring documentation。
中详细了解它们我忘了补充一点,使用Logback Access可能会有一个更简单的解决方案,这是一个从logback到记录有关请求和响应的信息的小型库。