我有一个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));
    }
}

09-27 10:05