Article directory
1. Dependency
<dependencies>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.79</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2. fr 配置
application.yml
server:
port: 8080
spring:
application:
name: springboot-kafka
kafka:
bootstrap-servers: 192.168.92.137:9092
producer:
batch-size: 16384
buffer-memory: 33544432
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer
consumer:
group-id: default_consumer_group
auto-commit-interval: 1000
auto-offset-reset: earliest
enable-auto-commit: true
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
3. Test class
package com.gblfy.elk.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class KafkaController {
@GetMapping("/healthAdvice")
public String healthAdvice() {
return "healthAdvice";
}
@GetMapping("/errorAdvice")
public String errorAdvice(@RequestParam("userId") Integer userId) {
Integer i = 1 / userId;
return "success";
}
}
4. aop interception
Demo:
AOP pre-notification
post-notification
exception notification
package com.gblfy.elk.aop;
import com.alibaba.fastjson.JSONObject;
import com.gblfy.elk.queue.AsynConcurrentQueue;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
@Aspect
@Component
public class AopLogAspect {
@Value("${server.port}")
private String serverPort;
// 申明一个切点 里面是 execution表达式
@Pointcut("execution(* com.gblfy.elk.controller.*.*(..))")
private void serviceAspect() {
}
@Autowired
private AsynConcurrentQueue asynConcurrentQueue;
// 请求method前打印内容
@Before(value = "serviceAspect()")
public void methodBefore(JoinPoint joinPoint) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
JSONObject jsonObject = new JSONObject();
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// 设置日期格式
jsonObject.put("request_time", df.format(new Date()));
jsonObject.put("request_url", request.getRequestURL().toString());
jsonObject.put("request_method", request.getMethod());
jsonObject.put("signature", joinPoint.getSignature());
jsonObject.put("request_args", Arrays.toString(joinPoint.getArgs()));
// IP地址信息
jsonObject.put("ip_addres", getIpAddr(request) + ":" + serverPort);
JSONObject requestJsonObject = new JSONObject();
requestJsonObject.put("request", jsonObject);
// 将日志信息投递到kafka中
String log = requestJsonObject.toJSONString();
asynConcurrentQueue.put(log);
}
// 在方法执行完结后打印返回内容
@AfterReturning(returning = "o", pointcut = "serviceAspect()")
public void methodAfterReturing(Object o) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
JSONObject respJSONObject = new JSONObject();
JSONObject jsonObject = new JSONObject();
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// 设置日期格式
jsonObject.put("response_time", df.format(new Date()));
jsonObject.put("response_content", JSONObject.toJSONString(o));
// IP地址信息
jsonObject.put("ip_addres", getIpAddr(request) + ":" + serverPort);
respJSONObject.put("response", jsonObject);
asynConcurrentQueue.put(respJSONObject.toJSONString());
}
/**
* 异常通知
*
* @param point
*/
@AfterThrowing(pointcut = "serviceAspect()", throwing = "e")
public void serviceAspect(JoinPoint point, Exception e) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
JSONObject jsonObject = new JSONObject();
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// 设置日期格式
jsonObject.put("request_time", df.format(new Date()));
jsonObject.put("request_url", request.getRequestURL().toString());
jsonObject.put("request_method", request.getMethod());
jsonObject.put("signature", point.getSignature());
jsonObject.put("request_args", Arrays.toString(point.getArgs()));
jsonObject.put("error", e.toString());
// IP地址信息
jsonObject.put("ip_addres", getIpAddr(request) + ":" + serverPort);
JSONObject requestJsonObject = new JSONObject();
requestJsonObject.put("request", jsonObject);
// 将日志信息投递到kafka中
String log = requestJsonObject.toJSONString();
asynConcurrentQueue.put(log);
}
public static String getIpAddr(HttpServletRequest request) {
//X-Forwarded-For(XFF)是用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段。
String ipAddress = request.getHeader("x-forwarded-for");
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getRemoteAddr();
if (ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")) {
//根据网卡取本机配置的IP
InetAddress inet = null;
try {
inet = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
ipAddress = inet.getHostAddress();
}
}
//对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
if (ipAddress != null && ipAddress.length() > 15) {
//"***.***.***.***".length() = 15
if (ipAddress.indexOf(",") > 0) {
ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
}
}
return ipAddress;
}
}
5. Concurrent queue sends MQ asynchronously
Sending messages asynchronously to MQ is used here to solve the delay problem caused by synchronously sending messages to MQ and the business thread belonging to the same main thread.
package com.gblfy.elk.queue;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
@Component
public class AsynConcurrentQueue {
private static BlockingDeque<String> logDeque = new LinkedBlockingDeque<>();
@Autowired
private KafkaTemplate<String, Object> kafkaTemplate;
public AsynConcurrentQueue() {
// 初始化
new AsynConcurrentQueue.LogThreadKafka().start();
}
/**
* 存入日志
*
* @param log
*/
public void put(String log) {
logDeque.offer(log);
}
class LogThreadKafka extends Thread {
@Override
public void run() {
while (true) {
String log = logDeque.poll();
if (!StringUtils.isEmpty(log)) {
// 将消息投递kafka中
kafkaTemplate.send("mayikt-log", log);
}
}
}
}
}
6. Encapsulate json message
{
"request_args": "[0]",
"request_method": "GET",
"error": "java.lang.ArithmeticException: / by zero",
"ip_addres": "192.168.92.1:8080",
"request_url": "http://localhost:8080/errorAdvice"
}
7. Complete encapsulation of json messages
{
"request": {
"request_time": "2022-03-11 20:45:50",
"signature": {
"declaringType": "com.gblfy.elk.controller.KafkaController",
"declaringTypeName": "com.gblfy.elk.controller.KafkaController",
"exceptionTypes": [],
"method": {
"accessible": false,
"annotatedExceptionTypes": [],
"annotatedParameterTypes": [
{
"annotations": [],
"declaredAnnotations": [],
"type": "java.lang.Integer"
}
],
"annotatedReceiverType": {
"annotations": [],
"declaredAnnotations": [],
"type": "com.gblfy.elk.controller.KafkaController"
},
"annotatedReturnType": {
"annotations": [],
"declaredAnnotations": [],
"type": "java.lang.String"
},
"annotations": [
{
"path": [],
"headers": [],
"name": "",
"produces": [],
"params": [],
"value": [
"/errorAdvice"
],
"consumes": []
}
],
"bridge": false,
"declaringClass": "com.gblfy.elk.controller.KafkaController",
"default": false,
"exceptionTypes": [],
"genericExceptionTypes": [],
"genericParameterTypes": [
"java.lang.Integer"
],
"genericReturnType": "java.lang.String",
"modifiers": 1,
"name": "errorAdvice",
"parameterAnnotations": [
[
{
"name": "",
"value": "userId",
"defaultValue": "\n\t\t\n\t\t\n\n\t\t\t\t\n",
"required": true
}
]
],
"parameterCount": 1,
"parameterTypes": [
"java.lang.Integer"
],
"returnType": "java.lang.String",
"synthetic": false,
"typeParameters": [],
"varArgs": false
},
"modifiers": 1,
"name": "errorAdvice",
"parameterNames": [
"userId"
],
"parameterTypes": [
"java.lang.Integer"
],
"returnType": "java.lang.String"
},
"request_args": "[0]",
"request_method": "GET",
"error": "java.lang.ArithmeticException: / by zero",
"ip_addres": "192.168.92.1:8080",
"request_url": "http://localhost:8080/errorAdvice"
}
}
GET /mayikt_logs/_search