Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
D
device-new-platform
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
赵啸非
device-new-platform
Commits
a658a419
Commit
a658a419
authored
Apr 25, 2022
by
赵啸非
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
修改消息组件
parent
01b49a93
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
146 additions
and
218 deletions
+146
-218
device-manager/src/main/java/com/mortals/xhx/base/framework/aspect/RequestLogAspect.java
...m/mortals/xhx/base/framework/aspect/RequestLogAspect.java
+0
-210
device-manager/src/main/java/com/mortals/xhx/base/framework/aspect/WebLogAspect.java
...a/com/mortals/xhx/base/framework/aspect/WebLogAspect.java
+103
-0
device-manager/src/main/resources/logback-spring.xml
device-manager/src/main/resources/logback-spring.xml
+24
-8
device-manager/src/main/resources/spy.properties
device-manager/src/main/resources/spy.properties
+19
-0
No files found.
device-manager/src/main/java/com/mortals/xhx/base/framework/aspect/RequestLogAspect.java
deleted
100644 → 0
View file @
01b49a93
package
com.mortals.xhx.base.framework.aspect
;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.serializer.SerializerFeature
;
import
com.mortals.framework.common.code.YesNo
;
import
com.mortals.framework.service.ICacheService
;
import
com.mortals.framework.util.StringUtils
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringEscapeUtils
;
import
org.aspectj.lang.ProceedingJoinPoint
;
import
org.aspectj.lang.annotation.Around
;
import
org.aspectj.lang.annotation.Aspect
;
import
org.aspectj.lang.reflect.MethodSignature
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.cglib.beans.BeanMap
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Profile
;
import
org.springframework.core.DefaultParameterNameDiscoverer
;
import
org.springframework.core.MethodParameter
;
import
org.springframework.core.ParameterNameDiscoverer
;
import
org.springframework.core.annotation.SynthesizingMethodParameter
;
import
org.springframework.core.io.InputStreamSource
;
import
org.springframework.web.bind.annotation.PathVariable
;
import
org.springframework.web.bind.annotation.RequestBody
;
import
org.springframework.web.bind.annotation.RequestParam
;
import
org.springframework.web.context.request.RequestAttributes
;
import
org.springframework.web.context.request.RequestContextHolder
;
import
org.springframework.web.context.request.ServletRequestAttributes
;
import
org.springframework.web.context.request.WebRequest
;
import
org.springframework.web.multipart.MultipartFile
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
java.io.InputStream
;
import
java.lang.reflect.Method
;
import
java.util.*
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.atomic.AtomicBoolean
;
/**
* Spring boot 控制器 请求日志,方便代码调试
*
* @author zxfei
*/
@Slf4j
@Aspect
@Configuration
(
proxyBeanMethods
=
false
)
@Profile
({
"develop1"
})
public
class
RequestLogAspect
{
private
static
final
ParameterNameDiscoverer
PARAMETER_NAME_DISCOVERER
=
new
DefaultParameterNameDiscoverer
();
/**
* AOP 环切 控制器 R 返回值
*
* @param point JoinPoint
* @return Object
* @throws Throwable 异常
*/
@Around
(
"execution(* com.mortals..*Controller.*(..)) || execution(* com.mortals..*Feign.*(..))"
)
public
Object
aroundApi
(
ProceedingJoinPoint
point
)
throws
Throwable
{
MethodSignature
ms
=
(
MethodSignature
)
point
.
getSignature
();
Method
method
=
ms
.
getMethod
();
Object
[]
args
=
point
.
getArgs
();
// 请求参数处理
final
Map
<
String
,
Object
>
paraMap
=
new
HashMap
<>(
16
);
for
(
int
i
=
0
;
i
<
args
.
length
;
i
++)
{
// 读取方法参数
MethodParameter
methodParam
=
getMethodParameter
(
method
,
i
);
// PathVariable 参数跳过
PathVariable
pathVariable
=
methodParam
.
getParameterAnnotation
(
PathVariable
.
class
);
if
(
pathVariable
!=
null
)
{
continue
;
}
RequestBody
requestBody
=
methodParam
.
getParameterAnnotation
(
RequestBody
.
class
);
String
parameterName
=
methodParam
.
getParameterName
();
if
(
parameterName
.
equals
(
"binder"
))
{
continue
;
}
Object
value
=
args
[
i
];
// 如果是body的json则是对象
if
(
requestBody
!=
null
&&
value
!=
null
)
{
paraMap
.
putAll
(
BeanMap
.
create
(
value
));
continue
;
}
// 处理 List
if
(
value
instanceof
List
)
{
value
=
((
List
)
value
).
get
(
0
);
}
// 处理 参数
if
(
value
instanceof
HttpServletRequest
)
{
paraMap
.
putAll
(((
HttpServletRequest
)
value
).
getParameterMap
());
}
else
if
(
value
instanceof
WebRequest
)
{
paraMap
.
putAll
(((
WebRequest
)
value
).
getParameterMap
());
}
else
if
(
value
instanceof
MultipartFile
)
{
MultipartFile
multipartFile
=
(
MultipartFile
)
value
;
String
name
=
multipartFile
.
getName
();
String
fileName
=
multipartFile
.
getOriginalFilename
();
paraMap
.
put
(
name
,
fileName
);
}
else
if
(
value
instanceof
HttpServletResponse
)
{
}
else
if
(
value
instanceof
InputStream
)
{
}
else
if
(
value
instanceof
InputStreamSource
)
{
}
else
if
(
value
instanceof
List
)
{
List
<?>
list
=
(
List
<?>)
value
;
AtomicBoolean
isSkip
=
new
AtomicBoolean
(
false
);
for
(
Object
o
:
list
)
{
if
(
"StandardMultipartFile"
.
equalsIgnoreCase
(
o
.
getClass
().
getSimpleName
()))
{
isSkip
.
set
(
true
);
break
;
}
}
if
(
isSkip
.
get
())
{
paraMap
.
put
(
parameterName
,
"此参数不能序列化为json"
);
continue
;
}
}
else
{
// 参数名
RequestParam
requestParam
=
methodParam
.
getParameterAnnotation
(
RequestParam
.
class
);
String
paraName
;
if
(
requestParam
!=
null
&&
StringUtils
.
isNotBlank
(
requestParam
.
value
()))
{
paraName
=
requestParam
.
value
();
}
else
{
paraName
=
methodParam
.
getParameterName
();
}
paraMap
.
put
(
paraName
,
value
);
}
}
RequestAttributes
requestAttributes
=
RequestContextHolder
.
getRequestAttributes
();
HttpServletRequest
request
=
(
requestAttributes
==
null
)
?
null
:
((
ServletRequestAttributes
)
requestAttributes
).
getRequest
();
String
requestURI
=
Objects
.
requireNonNull
(
request
).
getRequestURI
();
String
requestMethod
=
request
.
getMethod
();
// 构建成一条长 日志,避免并发下日志错乱
StringBuilder
beforeReqLog
=
new
StringBuilder
(
300
);
// 日志参数
List
<
Object
>
beforeReqArgs
=
new
ArrayList
<>();
//beforeReqLog.append("\n\n================ Request Start ================\n");
// 打印路由
beforeReqLog
.
append
(
"Request ===> {}: {}"
);
beforeReqArgs
.
add
(
requestMethod
);
beforeReqArgs
.
add
(
requestURI
);
// 请求参数
if
(
paraMap
.
isEmpty
())
{
beforeReqLog
.
append
(
"\n"
);
}
else
{
beforeReqLog
.
append
(
" Parameters: {}\n"
);
beforeReqArgs
.
add
(
JSON
.
toJSONString
(
paraMap
,
SerializerFeature
.
DisableCircularReferenceDetect
));
}
// 打印请求头
/* Enumeration<String> headers = request.getHeaderNames();
while (headers.hasMoreElements()) {
String headerName = headers.nextElement();
String headerValue = request.getHeader(headerName);
beforeReqLog.append("===Headers=== {} : {}\n");
beforeReqArgs.add(headerName);
beforeReqArgs.add(headerValue);
}*/
//beforeReqLog.append("================ Request End ================\n");
// 打印执行时间
long
startNs
=
System
.
nanoTime
();
log
.
info
(
beforeReqLog
.
toString
(),
beforeReqArgs
.
toArray
());
// aop 执行后的日志
StringBuilder
afterReqLog
=
new
StringBuilder
(
200
);
// 日志参数
List
<
Object
>
afterReqArgs
=
new
ArrayList
<>();
//afterReqLog.append("\n\n================ Response Start ================\n");
try
{
Object
result
=
point
.
proceed
();
// 打印返回结构体
afterReqLog
.
append
(
"Response===> {}\n"
);
afterReqArgs
.
add
(
StringEscapeUtils
.
unescapeJava
(
JSON
.
toJSONString
(
result
,
SerializerFeature
.
DisableCircularReferenceDetect
)));
return
result
;
}
finally
{
long
tookMs
=
TimeUnit
.
NANOSECONDS
.
toMillis
(
System
.
nanoTime
()
-
startNs
);
afterReqLog
.
append
(
"=== {}: {} ({} ms)\n"
);
afterReqArgs
.
add
(
requestMethod
);
afterReqArgs
.
add
(
requestURI
);
afterReqArgs
.
add
(
tookMs
);
//afterReqLog.append("================ Response End ================\n");
log
.
info
(
afterReqLog
.
toString
(),
afterReqArgs
.
toArray
());
}
}
/**
* 获取方法参数信息
*
* @param method 方法
* @param parameterIndex 参数序号
* @return {MethodParameter}
*/
public
MethodParameter
getMethodParameter
(
Method
method
,
int
parameterIndex
)
{
MethodParameter
methodParameter
=
new
SynthesizingMethodParameter
(
method
,
parameterIndex
);
methodParameter
.
initParameterNameDiscovery
(
PARAMETER_NAME_DISCOVERER
);
return
methodParameter
;
}
public
static
void
main
(
String
[]
args
)
{
String
str
=
"execution(* com.mortals..*Controller.*(..) && "
+
"(@within(org.springframework.stereotype.Controller) || "
+
"@within(org.springframework.web.bind.annotation.RestController))"
;
System
.
out
.
println
(
str
);
}
}
\ No newline at end of file
device-manager/src/main/java/com/mortals/xhx/base/framework/aspect/WebLogAspect.java
0 → 100644
View file @
a658a419
package
com.mortals.xhx.base.framework.aspect
;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.JSONObject
;
import
lombok.extern.slf4j.Slf4j
;
import
org.aspectj.lang.JoinPoint
;
import
org.aspectj.lang.annotation.AfterReturning
;
import
org.aspectj.lang.annotation.Aspect
;
import
org.aspectj.lang.annotation.Before
;
import
org.aspectj.lang.annotation.Pointcut
;
import
org.slf4j.MDC
;
import
org.springframework.context.annotation.Profile
;
import
org.springframework.core.annotation.Order
;
import
org.springframework.stereotype.Component
;
import
org.springframework.web.context.request.RequestContextHolder
;
import
org.springframework.web.context.request.ServletRequestAttributes
;
import
org.springframework.web.util.ContentCachingRequestWrapper
;
import
javax.servlet.http.HttpServletRequest
;
import
java.net.URLDecoder
;
import
java.nio.charset.StandardCharsets
;
import
java.util.Map
;
/**
* 打印每个请求的入参、出参等信息
*
* @author: zxfei
* @date: 2022/4/20 9:24
*/
@Aspect
@Component
@Slf4j
@Order
(
1
)
@Profile
({
"default"
,
"develop"
,
"test"
})
public
class
WebLogAspect
{
@Pointcut
(
"execution(public * com.mortals..*Controller.*(..))"
)
public
void
webLog
()
{
}
@Pointcut
(
"execution(public * com.mortals.xhx.base.framework.exception.ExceptionHandle.*(..))"
)
public
void
exceptions
()
{
}
/**
* 只在进入controller时记录请求信息
*/
@Before
(
"webLog()"
)
public
void
doBefore
(
JoinPoint
joinPoint
)
{
ServletRequestAttributes
attributes
=
(
ServletRequestAttributes
)
RequestContextHolder
.
getRequestAttributes
();
HttpServletRequest
request
=
attributes
.
getRequest
();
// log.debug("请求路径 {} ,进入方法 {}", request.getRequestURI(), joinPoint.getSignature().getDeclaringTypeName() + ":" + joinPoint.getSignature().getName());
MDC
.
put
(
"req"
,
getRequestInfo
(
request
).
toJSONString
());
MDC
.
put
(
"startTime"
,
String
.
valueOf
(
System
.
currentTimeMillis
()));
}
/**
* 打印请求日志
*/
@AfterReturning
(
pointcut
=
"webLog()|| exceptions()"
,
returning
=
"result"
)
public
void
afterReturning
(
Object
result
)
{
ServletRequestAttributes
attributes
=
(
ServletRequestAttributes
)
RequestContextHolder
.
getRequestAttributes
();
HttpServletRequest
request
=
attributes
.
getRequest
();
Map
<
String
,
String
>
map
=
MDC
.
getCopyOfContextMap
();
if
(
map
!=
null
&&
result
!=
null
)
{
String
startTime
=
map
.
getOrDefault
(
"startTime"
,
String
.
valueOf
(
System
.
currentTimeMillis
()));
long
takeTime
=
(
System
.
currentTimeMillis
()
-
Long
.
parseLong
(
startTime
));
log
.
info
(
" \n 请求路径:{} \n 耗时:{}ms \n 请求报文:{} \n 响应报文:{}"
,
request
.
getRequestURI
(),
takeTime
,
map
.
getOrDefault
(
"req"
,
""
),
result
==
null
?
""
:
result
.
toString
());
}
}
/**
* 读取请求信息,如果是表单则转换为json
*/
private
JSONObject
getRequestInfo
(
HttpServletRequest
req
)
{
JSONObject
requestInfo
=
new
JSONObject
();
try
{
StringBuffer
requestURL
=
req
.
getRequestURL
();
requestInfo
.
put
(
"requestURL"
,
requestURL
);
String
method
=
req
.
getMethod
();
requestInfo
.
put
(
"method"
,
method
);
if
(
req
.
getQueryString
()
!=
null
)
{
requestInfo
.
put
(
"queryString"
,
URLDecoder
.
decode
(
req
.
getQueryString
(),
"UTF-8"
));
}
String
remoteAddr
=
req
.
getRemoteAddr
();
requestInfo
.
put
(
"remoteAddr"
,
remoteAddr
);
if
(
req
instanceof
ContentCachingRequestWrapper
)
{
ContentCachingRequestWrapper
wrapper
=
(
ContentCachingRequestWrapper
)
req
;
String
bodyStr
=
new
String
(
wrapper
.
getContentAsByteArray
(),
StandardCharsets
.
UTF_8
);
if
(
bodyStr
.
startsWith
(
"{"
))
{
JSONObject
jsonObject
=
JSON
.
parseObject
(
bodyStr
);
requestInfo
.
put
(
"requestBody"
,
jsonObject
);
}
}
}
catch
(
Exception
e
)
{
log
.
error
(
"解析请求失败"
,
e
);
requestInfo
.
put
(
"parseError"
,
e
.
getMessage
());
}
return
requestInfo
;
}
}
device-manager/src/main/resources/logback-spring.xml
View file @
a658a419
<?xml version="1.0" encoding="utf-8"?>
<configuration
scan=
"true"
scanPeriod=
"60 seconds"
debug=
"false"
>
<!-- 定义变量后,可以使“${}”来使用变量 source来源为spring 上下文信息 -->
<springProperty
scope=
"context"
name=
"springApplicationName"
source=
"spring.application.name"
/>
<springProperty
scope=
"context"
name=
"serverPort"
source=
"server.port"
/>
<springProperty
scope=
"context"
name=
"logFilePath"
source=
"application.log.path"
defaultValue=
"/mortals/app/logs"
/>
<springProperty
scope=
"context"
name=
"logLevel"
source=
"application.log.level"
defaultValue=
"INFO"
/>
<property
name=
"logFilePath"
value=
"${logFilePath:-/mortals/app/logs}"
/>
<property
name=
"logLevel"
value=
"${logLevel:-INFO}"
/>
<!-- appender用来格式化日志输出节点,有俩个属性name和class,class用来指定哪种输出策略,常用就是控制台输出策略和文件输出策略 -->
<!-- 控制台输出策略-->
<appender
name=
"console"
class=
"ch.qos.logback.core.ConsoleAppender"
>
<encoder>
<pattern>
%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%thread] [%.50c\(%L\)] - %msg%n
</pattern>
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>
%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%X{traceId}] [%thread] [%.50c\(%L\)] - %msg%n
</pattern>
</encoder>
</appender>
<!-- 文件输出策略-->
<appender
name=
"fileInfo"
class=
"ch.qos.logback.core.rolling.RollingFileAppender"
>
<encoder>
<pattern>
%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%thread] [%.50c\(%L\)] - %msg%n
</pattern>
<pattern>
%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%
X{traceId}] [%
thread] [%.50c\(%L\)] - %msg%n
</pattern>
</encoder>
<file>
${logFilePath}/${springApplicationName:-default}/${serverPort:-default}-info.log
</file>
<rollingPolicy
class=
"ch.qos.logback.core.rolling.TimeBasedRollingPolicy"
>
<!-- 文件保存策略-->
<fileNamePattern>
${logFilePath}/${springApplicationName:-default}/${serverPort:-default}-info.log.%d{yyyyMMdd}
</fileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>
15
</MaxHistory>
</rollingPolicy>
</appender>
<!-- 异常文件输出策略-->
<appender
name=
"fileError"
class=
"ch.qos.logback.core.rolling.RollingFileAppender"
>
<filter
class=
"ch.qos.logback.classic.filter.ThresholdFilter"
>
<level>
ERROR
</level>
</filter>
<encoder>
<pattern>
%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%thread] [%.50c\(%L\)] - %msg%n
</pattern>
<pattern>
%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%
X{traceId}] [%
thread] [%.50c\(%L\)] - %msg%n
</pattern>
</encoder>
<file>
${logFilePath}/${springApplicationName:-default}/${serverPort:-default}-error.log
</file>
<rollingPolicy
class=
"ch.qos.logback.core.rolling.TimeBasedRollingPolicy"
>
<fileNamePattern>
${logFilePath}/${springApplicationName:-default}/${serverPort:-default}-error.log.%d{yyyyMMdd}
</fileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>
15
</MaxHistory>
</rollingPolicy>
</appender>
<logger
name=
"com.mortals.xhx.module"
level=
"DEBUG"
additivity=
"false"
/>
<root
level=
"${logLevel}"
>
<appender-ref
ref=
"console"
/>
<appender-ref
ref=
"fileInfo"
/>
<appender-ref
ref=
"fileError"
/>
</root>
<logger
name=
"com.mortals.xhx.module"
level=
"INFO"
additivity=
"false"
>
<!--TRACE < DEBUG < INFO < WARN < ERROR < FATAL -->
<!--用来设置某一个包或者具体的某一个类的日志打印级别、以及指定<appender>。<logger>仅有一个name属性,一个可选的level和一个可选的additivity属性。-->
<!-- name 用来指定受此loger约束的某一个包或者具体的某一个类-->
<!-- level 用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。如果未设置此属性,那么当前logger将会继承上级的级别-->
<!-- additivity 是否向上级logger传递打印信息。默认是true。false:表示只用当前logger的appender-ref。true:表示当前logger的appender-ref和rootLogger的appender-ref都有效。-->
<logger
name=
"com.mortals"
level=
"INFO"
additivity=
"false"
>
<appender-ref
ref=
"console"
/>
<appender-ref
ref=
"fileInfo"
/>
<appender-ref
ref=
"fileError"
/>
</logger>
</configuration>
\ No newline at end of file
device-manager/src/main/resources/spy.properties
0 → 100644
View file @
a658a419
module.log
=
com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
logMessageFormat
=
com.mortals.xhx.base.framework.config.P6spySqlFormatConfig
#customLogMessageFormat=%(currentTime) | SQL耗时: %(executionTime) ms | 连接信息: %(category)-%(connectionId) | 执行语句: %(sql)
# 使用控制台记录sql
appender
=
com.p6spy.engine.spy.appender.Slf4JLogger
#appender=com.p6spy.engine.spy.appender.FileLogger
## 配置记录Log例外
#excludecategories=info,debug,result,batc,resultset
# 设置使用p6spy driver来做代理
deregisterdrivers
=
true
# 日期格式
dateformat
=
yyyy-MM-dd HH:mm:ss
# 实际驱动
driverlist
=
com.mysql.cj.jdbc.Driver
# 是否开启慢SQL记录
outagedetection
=
true
# 慢SQL记录标准 秒
outagedetectioninterval
=
2
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment