Browse Source

init from phab

xielq 4 years ago
parent
commit
558230c5f9

+ 41 - 0
README.md

@@ -0,0 +1,41 @@
+# Http Log Module
+Print logs of http request using spring aop
+
+### Instructions
+* Dependency
+```xml
+<dependency>
+    <groupId>com.uas.ps</groupId>
+    <artifactId>ps-httplog</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+</dependency>
+```
+* Configuration
+```java
+@EnableHttpLog
+public class Application {
+    // code
+}
+```
+
+* HTTP api
+```java
+@RestController
+@RequestMapping("/api")
+public class MyApi{
+    
+    @GetMapping("/test/{id}")
+    @HttpLog(exclude = {"age"}, includeHeaders = {"name"}, excludeResult = true)
+    public Map<String, Object> test(@PathVariable("id") int id, 
+                                    @RequestParam("age") int age, 
+                                    @RequestHeader("name") String name, 
+                                    @RequestHeader("password") String password){
+        Map<String, Object> result = new HashMap<>();
+        result.put("id", id);
+        result.put("age", age);
+        result.put("name", name);
+        result.put("password", password);
+        return result;
+    }
+}
+```

+ 70 - 0
pom.xml

@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.uas.ps</groupId>
+        <artifactId>ps-parent</artifactId>
+        <version>0.0.1-SNAPSHOT</version>
+    </parent>
+    <artifactId>ps-httplog</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.uas.ps</groupId>
+            <artifactId>ps-core</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>*</groupId>
+                    <artifactId>*</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>*</groupId>
+                    <artifactId>*</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.aspectj</groupId>
+            <artifactId>aspectjweaver</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-web</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>*</groupId>
+                    <artifactId>*</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-source-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 37 - 0
src/main/java/com/uas/ps/httplog/annotation/HttpLog.java

@@ -0,0 +1,37 @@
+package com.uas.ps.httplog.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * print logs of http request
+ *
+ * @author sunyj
+ * @since 2018/2/5 9:57
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HttpLog {
+
+    /**
+     * parameters which is excluded
+     */
+    String[] exclude() default {};
+
+    /**
+     * specify the headers to print
+     */
+    String[] includeHeaders() default {};
+
+    /**
+     * don't print result
+     */
+    boolean excludeResult() default false;
+
+    /**
+     * print stack trace after throwing
+     */
+    boolean printStackTrace() default false;
+}

+ 20 - 0
src/main/java/com/uas/ps/httplog/config/EnableHttpLog.java

@@ -0,0 +1,20 @@
+package com.uas.ps.httplog.config;
+
+import org.springframework.context.annotation.Import;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * enable logs printing
+ *
+ * @author sunyj
+ * @since 2018/2/5 10:07
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Import(HttpLogConfiguration.class)
+public @interface EnableHttpLog {
+}

+ 20 - 0
src/main/java/com/uas/ps/httplog/config/HttpLogConfiguration.java

@@ -0,0 +1,20 @@
+package com.uas.ps.httplog.config;
+
+import com.uas.ps.httplog.intercept.HttpLogIntercept;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * configurations of printing logs
+ *
+ * @author sunyj
+ * @since 2018/2/5 10:15
+ */
+@Configuration
+public class HttpLogConfiguration {
+
+    @Bean
+    public HttpLogIntercept httpLogAspect() {
+        return new HttpLogIntercept();
+    }
+}

+ 181 - 0
src/main/java/com/uas/ps/httplog/intercept/HttpLogIntercept.java

@@ -0,0 +1,181 @@
+package com.uas.ps.httplog.intercept;
+
+import com.uas.ps.core.util.CollectionUtils;
+import com.uas.ps.core.util.IpHelper;
+import com.uas.ps.core.util.StringUtils;
+import com.uas.ps.httplog.annotation.HttpLog;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.*;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import java.lang.reflect.Method;
+import java.util.*;
+
+/**
+ * listen http request using AOP
+ *
+ * @author sunyj
+ * @since 2018/2/5 10:17
+ */
+@Aspect
+public class HttpLogIntercept {
+
+    private Logger logger = LoggerFactory.getLogger(getClass());
+
+    /**
+     * trace id
+     */
+    private ThreadLocal<String> traceIdThreadLocal = new ThreadLocal<>();
+
+    /**
+     * request time
+     */
+    private ThreadLocal<Long> requestTimeThreadLocal = new ThreadLocal<>();
+
+    @Pointcut("@annotation(com.uas.ps.httplog.annotation.HttpLog) " +
+            "&& (@annotation(org.springframework.web.bind.annotation.RequestMapping)" +
+            "|| @annotation(org.springframework.web.bind.annotation.GetMapping)" +
+            "|| @annotation(org.springframework.web.bind.annotation.PostMapping)" +
+            "|| @annotation(org.springframework.web.bind.annotation.DeleteMapping)" +
+            "|| @annotation(org.springframework.web.bind.annotation.PutMapping)" +
+            "|| @annotation(org.springframework.web.bind.annotation.PatchMapping))")
+    public void log() {
+    }
+
+    @Before("log()")
+    public void beforeRequest(JoinPoint joinPoint) {
+        try {
+            HttpLog httpLog = getAnnotation(joinPoint);
+            if (httpLog == null) {
+                return;
+            }
+            HttpServletRequest request = getRequest();
+            // assign one uuid to this request
+            traceIdThreadLocal.set(UUID.randomUUID().toString());
+            requestTimeThreadLocal.set(System.currentTimeMillis());
+
+            // print trace id, requested url, source ip
+            StringBuilder message = new StringBuilder();
+            message.append("Request... ")
+                    .append("traceId:").append(traceIdThreadLocal.get())
+                    .append(", url:").append(getRequestPath(request))
+                    .append(", method:").append(request.getMethod())
+                    .append(", ip:").append(IpHelper.getIp(request));
+
+            // print request parameters excluding the specified
+            List<String> exclude = httpLog.exclude().length > 0 ? Arrays.asList(httpLog.exclude()) : new ArrayList<String>();
+            if (!CollectionUtils.isEmpty(request.getParameterMap())) {
+                message.append(", params:{");
+                Set<Map.Entry<String, String[]>> entries = request.getParameterMap().entrySet();
+                for (Map.Entry<String, String[]> entry : entries) {
+                    String key = entry.getKey();
+                    if (!exclude.contains(key))
+                        if (!message.toString().endsWith(", params:{")) {
+                            message.append(", ");
+                        }
+                    message.append(key).append("=").append(toString(entry.getValue()));
+                }
+                message.append("}");
+            }
+
+            // print specified headers
+            List<String> includeHeaders = httpLog.includeHeaders().length < 1 ? new ArrayList<String>() : Arrays.asList(httpLog.includeHeaders());
+            if (includeHeaders.size() > 0) {
+                message.append(", headers:{");
+                for (String includeHeader : includeHeaders) {
+                    if (!message.toString().endsWith(", headers:{")) {
+                        message.append(", ");
+                    }
+                    message.append(includeHeader).append("=").append(request.getHeader(includeHeader));
+                }
+                message.append("}");
+            }
+            logger.info(message.toString());
+        } catch (Exception e) {
+            logger.error("Failed to print http log", e);
+        }
+    }
+
+    @AfterReturning(pointcut = "log()", returning = "result")
+    public void afterRequest(JoinPoint joinPoint, Object result) {
+        try {
+            HttpLog httpLog = getAnnotation(joinPoint);
+            if (httpLog != null) {
+                // print trace id, time spent, result
+                StringBuilder message = new StringBuilder();
+                message.append("Result... ")
+                        .append("traceId:").append(traceIdThreadLocal.get())
+                        .append(", spent:").append(System.currentTimeMillis() - requestTimeThreadLocal.get()).append("ms");
+                if (!httpLog.excludeResult()) {
+                    message.append(", result:").append(result);
+                }
+                logger.info(message.toString());
+            }
+        } catch (Exception e) {
+            logger.error("Failed to print http log", e);
+        }
+    }
+
+    @AfterThrowing(pointcut = "log()", throwing = "exception")
+    public void afterRequest(JoinPoint joinPoint, Exception exception) {
+        try {
+            HttpLog httpLog = getAnnotation(joinPoint);
+            if (httpLog != null) {
+                // print trace id, time spent, exception
+                StringBuilder message = new StringBuilder();
+                message.append("Result... ")
+                        .append("traceId:").append(traceIdThreadLocal.get())
+                        .append(", spent:").append(System.currentTimeMillis() - requestTimeThreadLocal.get()).append("ms");
+                if (httpLog.printStackTrace()) {
+                    logger.error(message.toString(), exception);
+                } else {
+                    message.append("\n").append(exception.toString());
+                    logger.error(message.toString());
+                }
+            }
+        } catch (Exception e) {
+            logger.error("Failed to print http log", e);
+        }
+    }
+
+    /**
+     * get HttpLog annotation
+     */
+    private HttpLog getAnnotation(JoinPoint joinPoint) {
+        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
+        Method method = methodSignature.getMethod();
+        return method.getAnnotation(HttpLog.class);
+    }
+
+    /**
+     * get HttpServletRequest
+     */
+    private HttpServletRequest getRequest() {
+        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+    }
+
+    /**
+     * get requested path
+     */
+    private String getRequestPath(HttpServletRequest request) {
+        return !StringUtils.isEmpty(request.getServletPath()) ? request.getServletPath() : request.getPathInfo();
+    }
+
+    /**
+     * convert an array to str
+     */
+    private String toString(Object[] array) {
+        if (array == null || array.length == 0) {
+            return null;
+        } else if (array.length == 1) {
+            return String.valueOf(array[0]);
+        } else {
+            return Arrays.toString(array);
+        }
+    }
+}