Helius
2021-06-29 5252d1396e21a16774be699a5ba1c8d39c14a22e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
package com.xzx.gc.filter;
 
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.text.StrBuilder;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.extra.emoji.EmojiUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.xzx.gc.common.constant.CommonEnum;
import com.xzx.gc.common.constant.MqConstants;
import com.xzx.gc.common.dto.log.*;
import com.xzx.gc.common.exception.BusinessException;
import com.xzx.gc.common.exception.PlatformException;
import com.xzx.gc.common.exception.RestException;
import com.xzx.gc.common.utils.*;
import com.xzx.gc.entity.CoreUser;
import com.xzx.gc.interceptor.SqlInterceptor;
import com.xzx.gc.model.MiException;
import com.xzx.gc.util.SessionUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.mapping.SqlCommandType;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
 
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.List;
import java.util.stream.Collectors;
 
 
/**
 * 日志切面
 */
@Aspect
@Component
@Slf4j
public class LogFilter {
 
 
    public static  final String AROUND_PARAM="aroundParam";
 
    //错误异常打印行数
    public static  final int ERR_LINE=50000;
    @Autowired
    private BusinessUtil businessUtil;
 
    @Autowired
    private SpringUtil springUtil;
 
    @Autowired
    private MqUtil mqUtil;
 
    /** 以 controller 包下定义的所有请求为切入点 */
    @Pointcut("execution(public * com.xzx.gc.*.controller..*.*(..))")
    public void webLog() {}
 
    /**
     * 在切点之前织入
     * @param joinPoint
     * @throws Throwable
     */
    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
 
    }
 
    /**
     * 在切点之后织入
     * @throws Throwable
     */
    @After("webLog()")
    public void doAfter() throws Throwable {
    }
 
    /**
     * 环绕
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("webLog()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = springUtil.getCurrentRequest();
        Dict dict = get(joinPoint,request);
        request.setAttribute(AROUND_PARAM,dict);
        // 开始打印请求日志
        String userId = request.getHeader("userId");
        if(StringUtils.isNotBlank(userId)){
            String ip = IpUtils.getIpAddr(request);
            businessUtil.saveLoginInfoToRedis(ip,userId);
        }
        Object result = joinPoint.proceed();
        String resultJson = businessUtil.prettyOut(result);
 
        //返回结果处理
        List<SqlDto> sqlList = (List<SqlDto>) request.getAttribute(SqlInterceptor.SQL_PARAM);
        // 执行耗时
        Long startTime = dict.getLong("startTime");
        long l = System.currentTimeMillis() - startTime;
 
 
        IntefaceAdminLog intefaceAdminLog = (IntefaceAdminLog) dict.get("inteface");
        intefaceAdminLog.setRunTime(Convert.toStr(l));
        intefaceAdminLog.setLogLevel(CommonEnum.调试级别.getValue());
        intefaceAdminLog.setOutParameter(EmojiUtil.removeAllEmojis(resultJson));
 
        if(CollUtil.isNotEmpty(sqlList)){
            String sql=sqlList.stream().map(x->x.getSql()).collect(Collectors.joining(";"));
            intefaceAdminLog.setSqlParameter(sql);
        }
 
        //不是后台请求才发送info日志队列
 
 
//        if(SpringUtil.isTest()||SpringUtil.isCheck()||SpringUtil.isDev()){
//            mqUtil.send(MqConstants.INTEFACE_ADMIN_LOG_QUEUE, intefaceAdminLog);
//        }else {
//            if (!dict.getBool("isAdmin")) {
//                mqUtil.send(MqConstants.INTEFACE_ADMIN_LOG_QUEUE, intefaceAdminLog);
////            OperationAppLog operationAppLog = (OperationAppLog) dict.get("operation");
////            mqUtil.send(MqConstants.OPERATION_APP_LOG_QUEUE, operationAppLog);
//            }
//        }
        mqUtil.send(MqConstants.INTEFACE_ADMIN_LOG_QUEUE, intefaceAdminLog);
        out(dict,sqlList,resultJson,l+"",CommonEnum.调试级别.getValue());
        clear(request);
        return result;
    }
 
 
    /**
     *
     * afterThrowable:(统一异常处理). <br/>
     *
     * @author fenglanglang
     * @param e
     */
    @AfterThrowing(pointcut="webLog()",throwing="e")
    public void afterThrowable(Throwable e) {
        HttpServletRequest request = springUtil.getCurrentRequest();
        if (request != null) {
            List<SqlDto> sqlList = (List<SqlDto>) request.getAttribute(SqlInterceptor.SQL_PARAM);
            Dict dict = (Dict) request.getAttribute(AROUND_PARAM);
            String l = null;
            if (dict != null) {
                Long startTime = dict.getLong("startTime");
                l = Convert.toStr(System.currentTimeMillis() - startTime);
                IntefaceAdminLog intefaceAdminLog = (IntefaceAdminLog) dict.get("inteface");
                intefaceAdminLog.setRunTime(Convert.toStr(l));
                String errMsg=null;
                String logLevel=CommonEnum.调试级别.getValue();
                if(e instanceof BusinessException){
                    errMsg=((BusinessException) e).getDebugMsg();
                    intefaceAdminLog.setLogLevel(CommonEnum.调试级别.getValue());
                    intefaceAdminLog.setOutParameter(errMsg);
                }else if(e instanceof RestException){
                    errMsg=((RestException) e).getMsg();
                    intefaceAdminLog.setLogLevel(CommonEnum.调试级别.getValue());
                    intefaceAdminLog.setOutParameter(errMsg);
                }else if(e instanceof MiException){
                    errMsg= e.getMessage();
                    intefaceAdminLog.setLogLevel(CommonEnum.调试级别.getValue());
                    intefaceAdminLog.setOutParameter(errMsg);
                }else {
                    if(SpringUtil.isDevOrTestOrCheck()){
                        errMsg = ExceptionUtil.stacktraceToString(e, ERR_LINE);
                    }else{
                        errMsg = ExceptionUtil.stacktraceToOneLineString(e, ERR_LINE);
                    }
                    intefaceAdminLog.setErrMessage(errMsg);
                    intefaceAdminLog.setLogLevel(CommonEnum.错误级别.getValue());
                    logLevel=CommonEnum.错误级别.getValue();
                }
                if (CollUtil.isNotEmpty(sqlList)) {
                    String sql = sqlList.stream().map(x -> x.getSql()).collect(Collectors.joining(";"));
                    intefaceAdminLog.setSqlParameter(sql);
                }
                mqUtil.send(MqConstants.INTEFACE_ADMIN_LOG_QUEUE, intefaceAdminLog);
//                if(!dict.getBool("isAdmin")){
//                    OperationAppLog operationAppLog = (OperationAppLog) dict.get("operation");
//                    mqUtil.send(MqConstants.OPERATION_APP_LOG_QUEUE, operationAppLog);
//                }
                out(dict, sqlList, errMsg, l, logLevel);
            }
            clear(request);
        }
    }
 
 
    /**
     * 组装
     * @param joinPoint
     * @return
     * @throws NoSuchMethodException
     */
    private Dict get(JoinPoint joinPoint,HttpServletRequest request) throws NoSuchMethodException {
        long startTime=System.currentTimeMillis();
        Dict dict=Dict.create();
        // 开始打印请求日志
        String clientType = request.getHeader("clientType");
        clientType=businessUtil.getClientTypeName(clientType);
 
        //接口描述
        String desc="";
        //接口所在模块
        String module="";
        Signature signature = joinPoint.getSignature();
        String methodName = signature.getName();
        //类
        Class declaringType = signature.getDeclaringType();
        String className = declaringType.getName();
        Class[] parameterTypes = ((MethodSignature)signature).getMethod().getParameterTypes();
        //方法
        Method method = declaringType.getMethod(signature.getName(),parameterTypes);
 
        if (method.isAnnotationPresent(ApiOperation.class)) {
            ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
            desc=apiOperation.value();
        }
 
//        if (declaringType.isAnnotationPresent(Api.class)) {
//            Api api = (Api) declaringType.getAnnotation(Api.class);
//            String[] tags = api.tags();
//            if(ArrayUtil.isNotEmpty(tags)){
//                module=tags[0];
//            }else {
//                module=desc;
//            }
//        }
 
        String inParam = businessUtil.prettyInParam(joinPoint.getArgs());
        String codePath=className+"."+methodName;
 
        boolean isAdmin = businessUtil.isAdmin(request.getRequestURI());
 
        String userId;
        if(isAdmin){
            CoreUser user= (CoreUser) request.getSession().getAttribute(SessionUtil.ACCESS_CURRENT_USER);
            userId=user!=null?user.getId().toString():"匿名";
        }else {
            userId = request.getHeader("userId");
            userId = StrUtil.isBlank(userId) ? "匿名" : userId;
        }
 
        String platName= isAdmin ?"后台接口":"前台接口";
 
 
        ConsoleDto in = in(request, desc, codePath, clientType,platName,inParam);
        dict.put("console",in);
 
 
        IntefaceAdminLog intefaceAdminLog =new IntefaceAdminLog();
        intefaceAdminLog.setMethodPath(request.getRequestURI());
        intefaceAdminLog.setMethodDesc(desc);
        intefaceAdminLog.setMethodName(className+"."+methodName);
        intefaceAdminLog.setIntoParameter(EmojiUtil.removeAllEmojis(inParam));
        intefaceAdminLog.setImplementType(isAdmin ?"2":"1");
        intefaceAdminLog.setUserId(userId);
 
        dict.put("inteface", intefaceAdminLog);
 
 
//        if(!isAdmin) {
//            OperationAppLog operationAppLog = new OperationAppLog();
//            operationAppLog.setOpreateName(userId);
//            if ("WEB".equals(clientType)) {
//                operationAppLog.setAppPrograme("1");
//            } else {
//                operationAppLog.setAppPrograme("2");
//            }
//            operationAppLog.setMethodName(module);
//            operationAppLog.setOperateAction(null);
//            dict.put("operation",operationAppLog);
//        }
 
 
        dict.put("startTime",startTime);
 
        dict.put("isAdmin",isAdmin);
        return dict;
    }
 
    /**
     * 清除
     * @param request
     */
    private void clear(HttpServletRequest request){
        request.removeAttribute(AROUND_PARAM);
        request.removeAttribute(SqlInterceptor.SQL_PARAM);
    }
 
    /**
     * 请求
     * @param request
     * @param desc
     * @param codePath
     * @param inParam
     * @return
     */
    private ConsoleDto in(HttpServletRequest request,String desc,String codePath,String clientType, String platName,String inParam){
        ConsoleDto consoleDto=new ConsoleDto();
 
        consoleDto.setTitle(businessUtil.checkProject(request.getRequestURI()));
        List<ConsoleContentDto> list=CollUtil.newArrayList();
        ConsoleContentDto consoleContentDto=new ConsoleContentDto();
        consoleContentDto.setName("请求地址");
        consoleContentDto.setValue(URLUtil.normalize(request.getRequestURL().toString()));
        list.add(consoleContentDto);
 
        consoleContentDto=new ConsoleContentDto();
        consoleContentDto.setName("请求描述");
        consoleContentDto.setValue(desc);
        list.add(consoleContentDto);
 
//        consoleContentDto=new ConsoleContentDto();
//        consoleContentDto.setName("请求方法");
//        consoleContentDto.setValue(request.getMethod());
//        list.add(consoleContentDto);
 
        consoleContentDto=new ConsoleContentDto();
        consoleContentDto.setName("请求接口");
        consoleContentDto.setValue(codePath);
        list.add(consoleContentDto);
 
        consoleContentDto=new ConsoleContentDto();
        consoleContentDto.setName("请求I P ");
        consoleContentDto.setValue(IpUtils.getIpAddr(request));
        list.add(consoleContentDto);
 
        consoleContentDto=new ConsoleContentDto();
        consoleContentDto.setName("请求平台");
        consoleContentDto.setValue(platName);
        list.add(consoleContentDto);
 
        consoleContentDto=new ConsoleContentDto();
        consoleContentDto.setName("请求来源");
        consoleContentDto.setValue(clientType);
        list.add(consoleContentDto);
 
 
        consoleContentDto=new ConsoleContentDto();
        consoleContentDto.setName("请求头部");
        consoleContentDto.setValue(businessUtil.prettyHeader(ServletUtil.getHeaderMap(request)));
        list.add(consoleContentDto);
 
        consoleContentDto=new ConsoleContentDto();
        consoleContentDto.setName("请求入参");
        consoleContentDto.setValue(inParam);
        list.add(consoleContentDto);
 
        consoleDto.setList(list);
 
        return consoleDto;
    }
 
    /**
     * 输出
     * @param dict
     * @param sqlList
     * @param resultJson
     * @param l
     */
    private void out(Dict dict, List<SqlDto> sqlList,String resultJson,String l,String type){
        ConsoleDto consoleDto= (ConsoleDto) dict.get("console");
        consoleDto.setHeader("您有新的请求");
        consoleDto.setEmjio("fish");
        List<ConsoleContentDto> list = consoleDto.getList();
 
        if(StrUtil.isNotBlank(resultJson)) {
            ConsoleContentDto consoleContentDto = new ConsoleContentDto();
            if(CommonEnum.调试级别.getValue().equals(type)) {
                consoleContentDto.setName("响应出参");
            }else if(CommonEnum.错误级别.getValue().equals(type)){
                consoleContentDto.setName("异常信息");
            }
            consoleContentDto.setValue(resultJson);
            list.add(consoleContentDto);
        }
 
        if(CollUtil.isNotEmpty(sqlList)) {
//            String sql=sqlList.stream().map(x->x.getSql()).collect(Collectors.joining(";\n                "));
//            long effectNum=sqlList.stream().mapToLong(x->Convert.toLong(x.getEffectNum())).sum();
            StrBuilder strBuilder = StrBuilder.create();
            for (int i = 0; i < sqlList.size(); i++) {
                SqlDto sqlDto = sqlList.get(i);
                strBuilder.append(sqlDto.getSql());
                strBuilder.append(";\n               ");
                if(SqlCommandType.SELECT.name().equals(sqlDto.getSqlType())){
                    strBuilder.append("【返回结果数:"+sqlDto.getEffectNum()+"】");
                }else {
                    strBuilder.append("【影响的行数:"+sqlDto.getEffectNum()+"】");
                }
 
                if(i!=sqlList.size()-1) {
                    strBuilder.append("\n               ");
                }
            }
            long costTime=sqlList.stream().mapToLong(x->Convert.toLong(x.getCostTime())).sum();
            ConsoleContentDto consoleContentDto = new ConsoleContentDto();
            consoleContentDto.setName("执行SQL ");
            consoleContentDto.setValue(strBuilder.toString());
            list.add(consoleContentDto);
 
            consoleContentDto=new ConsoleContentDto();
            consoleContentDto.setName("SQL耗时 ");
            consoleContentDto.setValue(costTime+"毫秒");
            list.add(consoleContentDto);
 
//            consoleContentDto=new ConsoleContentDto();
//            consoleContentDto.setName("影响行数");
//            consoleContentDto.setValue(effectNum+"");
//            list.add(consoleContentDto);
        }
 
 
        if(StrUtil.isNotBlank(l)) {
            ConsoleContentDto consoleContentDto = new ConsoleContentDto();
            consoleContentDto.setName("请求耗时");
            consoleContentDto.setValue(l + "毫秒");
            list.add(consoleContentDto);
        }
 
        ConsoleContentDto consoleContentDtoType = new ConsoleContentDto();
        consoleContentDtoType.setName("请求状态");
        if(CommonEnum.调试级别.getValue().equals(type)) {
            consoleContentDtoType.setValue("大吉大利今晚吃鸡!");
        }else if(CommonEnum.错误级别.getValue().equals(type)){
            consoleContentDtoType.setValue("又失败了我太难了!");
        }
        list.add(consoleContentDtoType);
 
        String console = businessUtil.console(consoleDto);
        log.debug(console);
 
    }
 
 
 
}