<commit_before>/*
 * Copyright (C) 2008 feilong
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.feilong.spring.web.servlet.interceptor.monitor;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeSet;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.time.StopWatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.feilong.core.date.DateExtensionUtil;
import com.feilong.core.date.TimeInterval;
import com.feilong.core.log.Slf4jUtil;
import com.feilong.core.tools.jsonlib.JsonUtil;
import com.feilong.core.util.Validator;
import com.feilong.servlet.http.RequestUtil;
import com.feilong.servlet.http.entity.RequestLogSwitch;
import com.feilong.spring.web.servlet.handler.HandlerMappingUtil;

/**
 * 监控每个 {@link HandlerMethod}执行的时间, 输出log到日志,这些日志级别可以单独开启到专门的日志文件.
 * 
 * <h3>如果不想用</h3>
 * 
 * <blockquote>
 * 该Interceptor本身对性能的影响几乎为0, 如果不想使用, 可以在spring Interceptor配置文件中去掉该配置
 * </blockquote>
 * 
 * @author feilong
 * @version 1.2.2 2015年7月18日 下午2:22:36
 * @since 1.2.2
 */
public class MonitorInterceptor extends HandlerInterceptorAdapter implements Ordered{

    /** The Constant LOGGER. */
    private static final Logger  LOGGER                = LoggerFactory.getLogger(MonitorInterceptor.class);

    /** 性能阀值<code>{@value}</code>,目前初步设置为1.5s,如果构建command 超过1.5s,会有 error log 记录. */
    private static final Integer PERFORMANCE_THRESHOLD = (int) (TimeInterval.MILLISECOND_PER_SECONDS * 1.5);

    /** The Constant STOPWATCH_ATTRIBUTE. */
    private static final String  STOPWATCH_ATTRIBUTE   = MonitorInterceptor.class.getName() + ".stopWatch";

    /*
     * (non-Javadoc)
     * 
     * @see org.springframework.web.servlet.handler.HandlerInterceptorAdapter#preHandle(javax.servlet.http.HttpServletRequest,
     * javax.servlet.http.HttpServletResponse, java.lang.Object)
     */
    @Override
    public boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler) throws Exception{
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        request.setAttribute(STOPWATCH_ATTRIBUTE, stopWatch);

        if (LOGGER.isDebugEnabled()){

            Map<String, Object> attributeMap = RequestUtil.getAttributeMap(request);

            RequestLogSwitch requestLogSwitch = new RequestLogSwitch();
            requestLogSwitch.setShowForwardInfos(true);

            Map<String, Object> requestInfoMapForLog = RequestUtil.getRequestInfoMapForLog(request, requestLogSwitch);

            if (LOGGER.isDebugEnabled()){
                LOGGER.debug(
                                "RequestInfoMapForLog:{},request attribute keys:{},spring VARIABLES map info:{},start StopWatch",
                                JsonUtil.format(requestInfoMapForLog),
                                JsonUtil.format(new TreeSet<String>(attributeMap.keySet())),
                                JsonUtil.format(HandlerMappingUtil.getHandlerMappingVariablesInfoForLog(request)));
            }
        }
        return super.preHandle(request, response, handler);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.springframework.web.servlet.handler.HandlerInterceptorAdapter#postHandle(javax.servlet.http.HttpServletRequest,
     * javax.servlet.http.HttpServletResponse, java.lang.Object, org.springframework.web.servlet.ModelAndView)
     */
    @Override
    public void postHandle(HttpServletRequest request,HttpServletResponse response,Object handler,ModelAndView modelAndView)
                    throws Exception{

        if (handler instanceof HandlerMethod){
            RequestLogSwitch requestLogSwitch = new RequestLogSwitch();
            requestLogSwitch.setShowForwardInfos(true);
            //requestLogSwitch.setShowIncludeInfos(true);
            //requestLogSwitch.setShowURLs(true);
            Map<String, Object> requestInfoMapForLog = RequestUtil.getRequestInfoMapForLog(request, requestLogSwitch);

            StopWatch stopWatch = (StopWatch) request.getAttribute(STOPWATCH_ATTRIBUTE);
            stopWatch.split();
            long useTime = stopWatch.getSplitTime();

            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            String methodName = method.getName();
            String className = method.getDeclaringClass().getSimpleName();

            if (LOGGER.isInfoEnabled()){
                String customerLog = "";
                if (Validator.isNotNullOrEmpty(modelAndView)){
                    String modelMapKeys = null == modelAndView.getModel() ? null : JsonUtil.format(new TreeSet<String>(modelAndView
                                    .getModel().keySet()));
                    String viewName = Validator.isNullOrEmpty(modelAndView.getView()) ? modelAndView.getViewName() : modelAndView.getView()
                                    .toString();
                    customerLog = Slf4jUtil.formatMessage("model keys:[{}],view:[{}]", modelMapKeys, viewName);
                }else{
                    customerLog = "modelAndView is null!!";
                }

                LOGGER.info(
                                "RequestInfoMapForLog:{},request attribute keys:{},customerLog:[{}],\n postHandle [{}.{}()] ",
                                JsonUtil.format(requestInfoMapForLog),
                                JsonUtil.format(new TreeSet<String>(RequestUtil.getAttributeMap(request).keySet())),
                                customerLog,
                                className,
                                methodName);
            }

            //**********************************************************************************
            boolean isMoreThanPerformanceThreshold = useTime > PERFORMANCE_THRESHOLD;
            String message = Slf4jUtil.formatMessage(
                            " [{}.{}()], use time:[{}],[{}] PERFORMANCE_THRESHOLD:[{}]",
                            className,
                            methodName,
                            DateExtensionUtil.getIntervalForView(useTime),
                            isMoreThanPerformanceThreshold ? ">" : "<=",
                            PERFORMANCE_THRESHOLD);

            //如果超过阀值, 那么以error的形式记录
            if (isMoreThanPerformanceThreshold){
                LOGGER.error(message);
                ServletContext servletContext = request.getSession().getServletContext();
                servletContext.log(message);
            }else{
                LOGGER.info(message);<commit_msg>MonitorInterceptor call formatSimpleMap<commit_after>/*
 * Copyright (C) 2008 feilong
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.feilong.spring.web.servlet.interceptor.monitor;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeSet;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.time.StopWatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.feilong.core.date.DateExtensionUtil;
import com.feilong.core.date.TimeInterval;
import com.feilong.core.log.Slf4jUtil;
import com.feilong.core.tools.jsonlib.JsonUtil;
import com.feilong.core.util.Validator;
import com.feilong.servlet.http.RequestUtil;
import com.feilong.servlet.http.entity.RequestLogSwitch;

/**
 * 监控每个 {@link HandlerMethod}执行的时间, 输出log到日志,这些日志级别可以单独开启到专门的日志文件.
 * 
 * <h3>如果不想用</h3>
 * 
 * <blockquote>
 * 该Interceptor本身对性能的影响几乎为0, 如果不想使用, 可以在spring Interceptor配置文件中去掉该配置
 * </blockquote>
 * 
 * @author feilong
 * @version 1.2.2 2015年7月18日 下午2:22:36
 * @since 1.2.2
 */
public class MonitorInterceptor extends HandlerInterceptorAdapter implements Ordered{

    /** The Constant LOGGER. */
    private static final Logger  LOGGER                = LoggerFactory.getLogger(MonitorInterceptor.class);

    /** 性能阀值<code>{@value}</code>,目前初步设置为1.5s,如果构建command 超过1.5s,会有 error log 记录. */
    private static final Integer PERFORMANCE_THRESHOLD = (int) (TimeInterval.MILLISECOND_PER_SECONDS * 1.5);

    /** The Constant STOPWATCH_ATTRIBUTE. */
    private static final String  STOPWATCH_ATTRIBUTE   = MonitorInterceptor.class.getName() + ".stopWatch";

    /*
     * (non-Javadoc)
     * 
     * @see org.springframework.web.servlet.handler.HandlerInterceptorAdapter#preHandle(javax.servlet.http.HttpServletRequest,
     * javax.servlet.http.HttpServletResponse, java.lang.Object)
     */
    @Override
    public boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler) throws Exception{
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        request.setAttribute(STOPWATCH_ATTRIBUTE, stopWatch);

        if (LOGGER.isDebugEnabled()){
            RequestLogSwitch requestLogSwitch = new RequestLogSwitch();
            requestLogSwitch.setShowForwardInfos(true);

            Map<String, Object> requestInfoMapForLog = RequestUtil.getRequestInfoMapForLog(request, requestLogSwitch);

            if (LOGGER.isDebugEnabled()){
                LOGGER.debug(
                                "RequestInfoMapForLog:{},request attribute keys:{},start StopWatch",
                                JsonUtil.format(requestInfoMapForLog),
                                JsonUtil.formatSimpleMap(RequestUtil.getAttributeMap(request)));
            }
        }
        return super.preHandle(request, response, handler);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.springframework.web.servlet.handler.HandlerInterceptorAdapter#postHandle(javax.servlet.http.HttpServletRequest,
     * javax.servlet.http.HttpServletResponse, java.lang.Object, org.springframework.web.servlet.ModelAndView)
     */
    @Override
    public void postHandle(HttpServletRequest request,HttpServletResponse response,Object handler,ModelAndView modelAndView)
                    throws Exception{

        if (handler instanceof HandlerMethod){
            RequestLogSwitch requestLogSwitch = new RequestLogSwitch();
            requestLogSwitch.setShowForwardInfos(true);

            Map<String, Object> requestInfoMapForLog = RequestUtil.getRequestInfoMapForLog(request, requestLogSwitch);

            StopWatch stopWatch = (StopWatch) request.getAttribute(STOPWATCH_ATTRIBUTE);
            stopWatch.split();
            long useTime = stopWatch.getSplitTime();

            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            String methodName = method.getName();
            String className = method.getDeclaringClass().getSimpleName();

            if (LOGGER.isInfoEnabled()){
                String customerLog = "";
                if (Validator.isNotNullOrEmpty(modelAndView)){
                    String modelMapKeys = null == modelAndView.getModel() ? null : JsonUtil.format(new TreeSet<String>(modelAndView
                                    .getModel().keySet()));
                    String viewName = Validator.isNullOrEmpty(modelAndView.getView()) ? modelAndView.getViewName() : modelAndView.getView()
                                    .toString();
                    customerLog = Slf4jUtil.formatMessage("model keys:[{}],view:[{}]", modelMapKeys, viewName);
                }else{
                    customerLog = "modelAndView is null!!";
                }

                LOGGER.info(
                                "RequestInfoMapForLog:{},request attribute keys:{},customerLog:[{}],\n postHandle [{}.{}()] ",
                                JsonUtil.format(requestInfoMapForLog),
                                JsonUtil.formatSimpleMap(RequestUtil.getAttributeMap(request)),
                                customerLog,
                                className,
                                methodName);
            }

            //**********************************************************************************
            boolean isMoreThanPerformanceThreshold = useTime > PERFORMANCE_THRESHOLD;
            String message = Slf4jUtil.formatMessage(
                            " [{}.{}()], use time:[{}],[{}] PERFORMANCE_THRESHOLD:[{}]",
                            className,
                            methodName,
                            DateExtensionUtil.getIntervalForView(useTime),
                            isMoreThanPerformanceThreshold ? ">" : "<=",
                            PERFORMANCE_THRESHOLD);

            //如果超过阀值, 那么以error的形式记录
            if (isMoreThanPerformanceThreshold){
                LOGGER.error(message);
                ServletContext servletContext = request.getSession().getServletContext();
                servletContext.log(message);
            }else{
                LOGGER.info(message);
{'fraction_non_alphanumeric': 0.10809119977756151, 'fraction_numerical': 0.005699986097594884, 'mean_word_length': 2.603055346857, 'pattern_counts': {'":': 0, '<': 26, '<?xml version=': 0, '>': 28, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '146257', 'n_tokens_mistral': 3937, 'n_tokens_neox': 3882, 'n_words': 711}