我有一个Spring应用程序,可以处理Web请求。每个请求方法如下所示
@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在生产中使用回溯绑定会生成许多有用的日志。
我希望这些日志包含在JsonLogger中,而不涉及所有基础类(有很多类),例如,使用方法JsonLogger.appendToResultLog(String txt)。我的第一个想法是创建我自己的包装slf4j绑定,在对logger.info,logger.error等方法的每次调用中展开栈跟踪,使用反射直到其余的控制器方法,并在其中追加日志字符串JsonLogger。
我有很强的发明自行车的感觉。是否有或多或少的标准方法可以达到所需的结果?
最佳答案
最终没有任何方面和思考-只是自定义的logback附加程序。
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));
}
}