Commit 8ef10799fb8f72d5c6255c27ce8f06aeac7d05f4
1 parent
7a101804
增加日志
Showing
11 changed files
with
473 additions
and
2 deletions
pom.xml
| ... | ... | @@ -50,6 +50,12 @@ |
| 50 | 50 | </exclusion> |
| 51 | 51 | </exclusions> |
| 52 | 52 | </dependency> |
| 53 | + | |
| 54 | + <!-- springboot websocket --> | |
| 55 | + <dependency> | |
| 56 | + <groupId>org.springframework.boot</groupId> | |
| 57 | + <artifactId>spring-boot-starter-websocket</artifactId> | |
| 58 | + </dependency> | |
| 53 | 59 | |
| 54 | 60 | <!-- 自动更新 --> |
| 55 | 61 | <dependency> | ... | ... |
src/main/java/com/cnlive/shenhe/ShenheApplication.java
| ... | ... | @@ -5,13 +5,25 @@ import org.jasig.cas.client.session.SingleSignOutFilter; |
| 5 | 5 | import org.jasig.cas.client.util.AssertionThreadLocalFilter; |
| 6 | 6 | import org.jasig.cas.client.util.HttpServletRequestWrapperFilter; |
| 7 | 7 | import org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter; |
| 8 | +import org.slf4j.Logger; | |
| 9 | +import org.slf4j.LoggerFactory; | |
| 10 | +import org.springframework.beans.factory.annotation.Value; | |
| 11 | +import org.springframework.boot.ApplicationRunner; | |
| 8 | 12 | import org.springframework.boot.SpringApplication; |
| 9 | 13 | import org.springframework.boot.autoconfigure.SpringBootApplication; |
| 10 | 14 | import org.springframework.boot.web.servlet.FilterRegistrationBean; |
| 11 | 15 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; |
| 12 | 16 | import org.springframework.context.annotation.Bean; |
| 17 | +import org.springframework.context.annotation.Configuration; | |
| 18 | +import org.springframework.stereotype.Controller; | |
| 19 | +import org.springframework.ui.Model; | |
| 20 | +import org.springframework.web.bind.annotation.GetMapping; | |
| 21 | +import org.springframework.web.servlet.ModelAndView; | |
| 22 | + | |
| 13 | 23 | import tk.mybatis.spring.annotation.MapperScan; |
| 14 | 24 | |
| 25 | +import java.net.InetAddress; | |
| 26 | +import java.net.UnknownHostException; | |
| 15 | 27 | import java.util.HashMap; |
| 16 | 28 | import java.util.Map; |
| 17 | 29 | |
| ... | ... | @@ -63,7 +75,7 @@ public class ShenheApplication extends SpringBootServletInitializer { |
| 63 | 75 | Map<String,String> initParameters = new HashMap<String, String>(); |
| 64 | 76 | initParameters.put("casServerLoginUrl", CAS_SERVER_LOGIN_URL); |
| 65 | 77 | initParameters.put("service", SERVICE_LOGIN); |
| 66 | - initParameters.put("ignorePattern", "/api/*"); | |
| 78 | + initParameters.put("ignorePattern", "/api/*|/logging/*"); | |
| 67 | 79 | registration.setInitParameters(initParameters); |
| 68 | 80 | // 设定加载的顺序 |
| 69 | 81 | registration.setOrder(2); |
| ... | ... | @@ -249,4 +261,43 @@ public class ShenheApplication extends SpringBootServletInitializer { |
| 249 | 261 | public static void main(String[] args) { |
| 250 | 262 | SpringApplication.run(ShenheApplication.class, args); |
| 251 | 263 | } |
| 264 | + | |
| 265 | + /** | |
| 266 | + * 配置内部类 | |
| 267 | + */ | |
| 268 | + @Controller | |
| 269 | + @Configuration | |
| 270 | + class Config { | |
| 271 | + | |
| 272 | + /** | |
| 273 | + * 获取日志对象,构造函数传入当前类,查找日志方便定位 | |
| 274 | + */ | |
| 275 | + private final Logger logger = LoggerFactory.getLogger(this.getClass()); | |
| 276 | + | |
| 277 | + @Value("${user.home}") | |
| 278 | + private String userName; | |
| 279 | + | |
| 280 | + /** | |
| 281 | + * 端口 | |
| 282 | + */ | |
| 283 | + @Value("${server.port}") | |
| 284 | + private String port; | |
| 285 | + /** | |
| 286 | + * 启动成功 | |
| 287 | + */ | |
| 288 | + @Bean | |
| 289 | + public ApplicationRunner applicationRunner() { | |
| 290 | + return applicationArguments -> { | |
| 291 | + try { | |
| 292 | + InetAddress ia = InetAddress.getLocalHost(); | |
| 293 | + //获取本机内网IP | |
| 294 | + logger.info("启动成功:" + "http://" + ia.getHostAddress() + ":" + port + "/"); | |
| 295 | + logger.info("${user.home} :" + userName); | |
| 296 | + } catch (UnknownHostException ex) { | |
| 297 | + ex.printStackTrace(); | |
| 298 | + } | |
| 299 | + }; | |
| 300 | + } | |
| 301 | + | |
| 302 | + } | |
| 252 | 303 | } | ... | ... |
src/main/java/com/cnlive/shenhe/api/AvsampleCallBackControllerApi.java
| ... | ... | @@ -10,12 +10,15 @@ import com.cnlive.shenhe.utils.CommonUtils; |
| 10 | 10 | import org.slf4j.Logger; |
| 11 | 11 | import org.slf4j.LoggerFactory; |
| 12 | 12 | import org.springframework.beans.factory.annotation.Autowired; |
| 13 | +import org.springframework.beans.factory.annotation.Value; | |
| 13 | 14 | import org.springframework.stereotype.Controller; |
| 15 | +import org.springframework.ui.Model; | |
| 14 | 16 | import org.springframework.web.bind.annotation.GetMapping; |
| 15 | 17 | import org.springframework.web.bind.annotation.PostMapping; |
| 16 | 18 | import org.springframework.web.bind.annotation.RequestBody; |
| 17 | 19 | import org.springframework.web.bind.annotation.RequestMapping; |
| 18 | 20 | import org.springframework.web.bind.annotation.ResponseBody; |
| 21 | +import org.springframework.web.servlet.ModelAndView; | |
| 19 | 22 | |
| 20 | 23 | import java.util.List; |
| 21 | 24 | |
| ... | ... | @@ -73,4 +76,5 @@ public class AvsampleCallBackControllerApi { |
| 73 | 76 | public String getGame(){ |
| 74 | 77 | return "html/game.html"; |
| 75 | 78 | } |
| 79 | + | |
| 76 | 80 | } | ... | ... |
src/main/java/com/cnlive/shenhe/logging/LoggingWSServer.java
0 → 100644
| 1 | +package com.cnlive.shenhe.logging; | |
| 2 | + | |
| 3 | + | |
| 4 | +import org.slf4j.Logger; | |
| 5 | +import org.slf4j.LoggerFactory; | |
| 6 | +import org.springframework.beans.factory.annotation.Value; | |
| 7 | +import org.springframework.stereotype.Component; | |
| 8 | +import org.thymeleaf.util.StringUtils; | |
| 9 | + | |
| 10 | + | |
| 11 | +import javax.websocket.*; | |
| 12 | +import javax.websocket.server.ServerEndpoint; | |
| 13 | +import java.io.BufferedReader; | |
| 14 | +import java.io.FileReader; | |
| 15 | +import java.io.IOException; | |
| 16 | +import java.text.SimpleDateFormat; | |
| 17 | +import java.util.Arrays; | |
| 18 | +import java.util.Date; | |
| 19 | +import java.util.Map; | |
| 20 | +import java.util.concurrent.ConcurrentHashMap; | |
| 21 | + | |
| 22 | +/** | |
| 23 | + * WebSocket获取实时日志并输出到Web页面 | |
| 24 | + */ | |
| 25 | +@Component | |
| 26 | +@ServerEndpoint(value = "/logging/websocket", configurator = MyEndpointConfigure.class) | |
| 27 | +public class LoggingWSServer { | |
| 28 | + private static Logger log = LoggerFactory.getLogger(LoggingWSServer.class); | |
| 29 | + | |
| 30 | + @Value("${spring.application.name}") | |
| 31 | + private String applicationName; | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * 连接集合 | |
| 35 | + */ | |
| 36 | + private static Map<String, Session> sessionMap = new ConcurrentHashMap<String, Session>(); | |
| 37 | + private static Map<String, Integer> lengthMap = new ConcurrentHashMap<String, Integer>(); | |
| 38 | + | |
| 39 | + /** | |
| 40 | + * 连接建立成功调用的方法 | |
| 41 | + */ | |
| 42 | + @OnOpen | |
| 43 | + public void onOpen(Session session) { | |
| 44 | + //添加到集合中 | |
| 45 | + sessionMap.put(session.getId(), session); | |
| 46 | + lengthMap.put(session.getId(), 1);//默认从第一行开始 | |
| 47 | + | |
| 48 | + //获取日志信息 | |
| 49 | + new Thread(() -> { | |
| 50 | + log.info("LoggingWebSocketServer 任务开始"); | |
| 51 | + boolean first = true; | |
| 52 | + while (sessionMap.get(session.getId()) != null) { | |
| 53 | + BufferedReader reader = null; | |
| 54 | + try { | |
| 55 | + //日志文件路径,获取最新的 | |
| 56 | + String filePath = System.getProperty("user.home") + "/log/" + new SimpleDateFormat("yyyyMMdd").format(new Date()) + "/"+applicationName+".log"; | |
| 57 | + | |
| 58 | + //字符流 | |
| 59 | + reader = new BufferedReader(new FileReader(filePath)); | |
| 60 | + Object[] lines = reader.lines().toArray(); | |
| 61 | + | |
| 62 | + //只取从上次之后产生的日志 | |
| 63 | + Object[] copyOfRange = Arrays.copyOfRange(lines, lengthMap.get(session.getId()), lines.length); | |
| 64 | + | |
| 65 | + //对日志进行着色,更加美观 PS:注意,这里要根据日志生成规则来操作 | |
| 66 | + for (int i = 0; i < copyOfRange.length; i++) { | |
| 67 | + String line = (String) copyOfRange[i]; | |
| 68 | + //先转义 | |
| 69 | + line = line.replaceAll("&", "&") | |
| 70 | + .replaceAll("<", "<") | |
| 71 | + .replaceAll(">", ">") | |
| 72 | + .replaceAll("\"", """); | |
| 73 | + | |
| 74 | + //处理等级 | |
| 75 | + line = line.replace("DEBUG", "<span style='color: blue;'>DEBUG</span>"); | |
| 76 | + line = line.replace("INFO", "<span style='color: green;'>INFO</span>"); | |
| 77 | + line = line.replace("WARN", "<span style='color: orange;'>WARN</span>"); | |
| 78 | + line = line.replace("ERROR", "<span style='color: red;'>ERROR</span>"); | |
| 79 | + | |
| 80 | + //处理类名 | |
| 81 | + String[] split = line.split("]"); | |
| 82 | + if (split.length >= 2) { | |
| 83 | + String[] split1 = split[1].split("-"); | |
| 84 | + if (split1.length >= 2) { | |
| 85 | + line = split[0] + "]" + "<span style='color: #298a8a;'>" + split1[0] + "</span>" + "-" + split1[1]; | |
| 86 | + } | |
| 87 | + } | |
| 88 | + | |
| 89 | + copyOfRange[i] = line; | |
| 90 | + } | |
| 91 | + | |
| 92 | + //存储最新一行开始 | |
| 93 | + lengthMap.put(session.getId(), lines.length); | |
| 94 | + | |
| 95 | + //第一次如果太大,截取最新的200行就够了,避免传输的数据太大 | |
| 96 | + if(first && copyOfRange.length > 200){ | |
| 97 | + copyOfRange = Arrays.copyOfRange(copyOfRange, copyOfRange.length - 200, copyOfRange.length); | |
| 98 | + first = false; | |
| 99 | + } | |
| 100 | + | |
| 101 | + String result = StringUtils.join(copyOfRange, "<br/>"); | |
| 102 | + | |
| 103 | + //发送 | |
| 104 | + send(session, result); | |
| 105 | + | |
| 106 | + //休眠一秒 | |
| 107 | + Thread.sleep(1000); | |
| 108 | + } catch (Exception e) { | |
| 109 | + //捕获但不处理 | |
| 110 | + e.printStackTrace(); | |
| 111 | + } finally { | |
| 112 | + try { | |
| 113 | + reader.close(); | |
| 114 | + } catch (IOException ignored) { | |
| 115 | + } | |
| 116 | + } | |
| 117 | + } | |
| 118 | + log.info("LoggingWebSocketServer 任务结束"); | |
| 119 | + }).start(); | |
| 120 | + } | |
| 121 | + | |
| 122 | + /** | |
| 123 | + * 连接关闭调用的方法 | |
| 124 | + */ | |
| 125 | + @OnClose | |
| 126 | + public void onClose(Session session) { | |
| 127 | + //从集合中删除 | |
| 128 | + sessionMap.remove(session.getId()); | |
| 129 | + lengthMap.remove(session.getId()); | |
| 130 | + } | |
| 131 | + | |
| 132 | + /** | |
| 133 | + * 发生错误时调用 | |
| 134 | + */ | |
| 135 | + @OnError | |
| 136 | + public void onError(Session session, Throwable error) { | |
| 137 | + error.printStackTrace(); | |
| 138 | + } | |
| 139 | + | |
| 140 | + /** | |
| 141 | + * 服务器接收到客户端消息时调用的方法 | |
| 142 | + */ | |
| 143 | + @OnMessage | |
| 144 | + public void onMessage(String message, Session session) { | |
| 145 | + | |
| 146 | + } | |
| 147 | + | |
| 148 | + /** | |
| 149 | + * 封装一个send方法,发送消息到前端 | |
| 150 | + */ | |
| 151 | + private void send(Session session, String message) { | |
| 152 | + try { | |
| 153 | + session.getBasicRemote().sendText(message); | |
| 154 | + } catch (Exception e) { | |
| 155 | + e.printStackTrace(); | |
| 156 | + } | |
| 157 | + } | |
| 158 | +} | ... | ... |
src/main/java/com/cnlive/shenhe/logging/MyEndpointConfigure.java
0 → 100644
| 1 | +package com.cnlive.shenhe.logging; | |
| 2 | + | |
| 3 | +import org.springframework.beans.BeansException; | |
| 4 | +import org.springframework.beans.factory.BeanFactory; | |
| 5 | +import org.springframework.context.ApplicationContext; | |
| 6 | +import org.springframework.context.ApplicationContextAware; | |
| 7 | + | |
| 8 | +import javax.websocket.server.ServerEndpointConfig; | |
| 9 | + | |
| 10 | +/** | |
| 11 | + * 解决注入其他类的问题,详情参考这篇帖子:webSocket无法注入其他类:https://blog.csdn.net/tornadojava/article/details/78781474 | |
| 12 | + */ | |
| 13 | +public class MyEndpointConfigure extends ServerEndpointConfig.Configurator implements ApplicationContextAware { | |
| 14 | + | |
| 15 | + private static volatile BeanFactory context; | |
| 16 | + | |
| 17 | + @Override | |
| 18 | + public <T> T getEndpointInstance(Class<T> clazz){ | |
| 19 | + return context.getBean(clazz); | |
| 20 | + } | |
| 21 | + | |
| 22 | + @Override | |
| 23 | + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { | |
| 24 | + MyEndpointConfigure.context = applicationContext; | |
| 25 | + } | |
| 26 | +} | ... | ... |
src/main/java/com/cnlive/shenhe/logging/WebSocketConfig.java
0 → 100644
| 1 | +package com.cnlive.shenhe.logging; | |
| 2 | + | |
| 3 | +import org.springframework.context.annotation.Bean; | |
| 4 | +import org.springframework.context.annotation.Configuration; | |
| 5 | +import org.springframework.web.socket.server.standard.ServerEndpointExporter; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * WebSocket配置 | |
| 9 | + */ | |
| 10 | +@Configuration | |
| 11 | +public class WebSocketConfig { | |
| 12 | + | |
| 13 | + | |
| 14 | + /** | |
| 15 | + * 用途:扫描并注册所有携带@ServerEndpoint注解的实例。 @ServerEndpoint("/websocket") | |
| 16 | + * PS:如果使用外部容器 则无需提供ServerEndpointExporter。 | |
| 17 | + */ | |
| 18 | + @Bean | |
| 19 | + public ServerEndpointExporter serverEndpointExporter() { | |
| 20 | + return new ServerEndpointExporter(); | |
| 21 | + } | |
| 22 | + | |
| 23 | + /** | |
| 24 | + * 支持注入其他类 | |
| 25 | + */ | |
| 26 | + @Bean | |
| 27 | + public MyEndpointConfigure newMyEndpointConfigure (){ | |
| 28 | + return new MyEndpointConfigure (); | |
| 29 | + } | |
| 30 | +} | ... | ... |
src/main/java/com/cnlive/shenhe/logging/logging.java
0 → 100644
| 1 | +package com.cnlive.shenhe.logging; | |
| 2 | + | |
| 3 | +import org.springframework.beans.factory.annotation.Value; | |
| 4 | +import org.springframework.stereotype.Controller; | |
| 5 | +import org.springframework.ui.Model; | |
| 6 | +import org.springframework.web.bind.annotation.GetMapping; | |
| 7 | +import org.springframework.web.bind.annotation.RequestMapping; | |
| 8 | +import org.springframework.web.servlet.ModelAndView; | |
| 9 | + | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * @Auther: 李伟 | |
| 13 | + * @Date: 2019/08/13 10:43 | |
| 14 | + * @Description:log实时日志 | |
| 15 | + */ | |
| 16 | +@Controller | |
| 17 | +@RequestMapping("/logging") | |
| 18 | +public class logging { | |
| 19 | + /** | |
| 20 | + * 端口 | |
| 21 | + */ | |
| 22 | + @Value("${server.port}") | |
| 23 | + private String port; | |
| 24 | + | |
| 25 | + /** | |
| 26 | + * 跳转实时日志 | |
| 27 | + */ | |
| 28 | + @GetMapping("/") | |
| 29 | + public ModelAndView logging( Model model) { | |
| 30 | + model.addAttribute("port", port); | |
| 31 | + return new ModelAndView("logging/logging.html"); | |
| 32 | + } | |
| 33 | +} | ... | ... |
src/main/java/com/cnlive/shenhe/utils/AntiFraudUtil.java
| ... | ... | @@ -42,7 +42,7 @@ public class AntiFraudUtil { |
| 42 | 42 | // String btId = uuid.toString(); |
| 43 | 43 | |
| 44 | 44 | // System.out.println("文本:"+AntiFraudUtil.filterText("0000001", "王八蛋", "DYNAMIC_USER") + "---"); |
| 45 | -// System.out.println(AntiFraudUtil.filterArticle("000111","http://3g.huabian.com/api/hz0227/show/388865.html",null)); | |
| 45 | +// System.out.println(AntiFraudUtil.filterArticle("000111","http://shineup.china.com.cn/WJJ/detail2_2019_08/13/1365957.html",null)); | |
| 46 | 46 | //System.out.println("图片:"+AntiFraudUtil.filterImg("0000001", jsonArray,"DYNAMIC_BUSINESS") + "---"); |
| 47 | 47 | //System.out.println("视频:"+AntiFraudUtil.filterVideo("http://wjj.ys1.cnliveimg.com/testVideo/test1.mp4",btId,null) + "---"); |
| 48 | 48 | //queryVideoResult("02b649b7-3451-403e-abd0-592302cec2a0"); | ... | ... |
src/main/resources/application.properties
| ... | ... | @@ -36,6 +36,8 @@ mybatis.mapper-locations=classpath:mapping/*.xml |
| 36 | 36 | mybatis.type-aliases-package=com.cnlive.shenhe.entity |
| 37 | 37 | server.port=82 |
| 38 | 38 | |
| 39 | +spring.application.name=cnlive_shenhe | |
| 40 | + | |
| 39 | 41 | sync_users_api=http://api.cnlive.com/open/api2/inner2/shenhe/getuser |
| 40 | 42 | sync_users_app_key=314a9dd4-a9b7-4c12-bbbe-1150a36491ae |
| 41 | 43 | ... | ... |
src/main/resources/logback-spring.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 2 | +<!-- | |
| 3 | +scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。 | |
| 4 | +scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒当scan为true时,此属性生效。默认的时间间隔为1分钟。 | |
| 5 | +debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 | |
| 6 | +--> | |
| 7 | +<configuration scan="false" scanPeriod="60 seconds" debug="false"> | |
| 8 | + <!--日志文件主目录:这里${user.home}为当前服务器用户主目录--> | |
| 9 | + <property name="LOG_HOME" value="${user.home}/log" /> | |
| 10 | + <!-- 定义日志文件名称 --> | |
| 11 | +<!-- <property name="appName" value="appName" source="spring.application.name"></property> --> | |
| 12 | + <!--日志文件名称:这里spring.application.name表示工程名称--> | |
| 13 | + <springProperty scope="context" name="APP_NAME" source="spring.application.name"/> | |
| 14 | + <!-- ch.qos.logback.core.ConsoleAppender 表示控制台输出 --> | |
| 15 | + <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"> | |
| 16 | + <!-- | |
| 17 | + 日志输出格式: | |
| 18 | + %d表示日期时间, | |
| 19 | + %thread表示线程名, | |
| 20 | + %-5level:级别从左显示5个字符宽度 | |
| 21 | + %logger{50} 表示logger名字最长50个字符,否则按照句点分割。 | |
| 22 | + %msg:日志消息, | |
| 23 | + %n是换行符 | |
| 24 | + --> | |
| 25 | + <layout class="ch.qos.logback.classic.PatternLayout"> | |
| 26 | + <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> | |
| 27 | + </layout> | |
| 28 | + </appender> | |
| 29 | + | |
| 30 | + <!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 --> | |
| 31 | + <appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"> | |
| 32 | + <!-- 指定日志文件的名称 --> | |
| 33 | +<!-- <file>${LOG_HOME}/%d{yyyyMMdd}/${APP_NAME}.log</file> --> | |
| 34 | + <!-- | |
| 35 | + 当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名 | |
| 36 | + TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。 | |
| 37 | + --> | |
| 38 | + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | |
| 39 | + <!-- | |
| 40 | + 滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动 | |
| 41 | + %i:当文件大小超过maxFileSize时,按照i进行文件滚动 | |
| 42 | + --> | |
| 43 | + <fileNamePattern>${LOG_HOME}/%d{yyyyMMdd}/${APP_NAME}.log</fileNamePattern> | |
| 44 | + <!-- | |
| 45 | + 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每天滚动, | |
| 46 | + 且maxHistory是365,则只保存最近365天的文件,删除之前的旧文件。注意,删除旧文件是, | |
| 47 | + 那些为了归档而创建的目录也会被删除。 | |
| 48 | + --> | |
| 49 | + <MaxHistory>30</MaxHistory> | |
| 50 | + <!-- | |
| 51 | + 当日志文件超过maxFileSize指定的大小是,根据上面提到的%i进行日志文件滚动 注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy | |
| 52 | + --> | |
| 53 | +<!-- <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> --> | |
| 54 | +<!-- <maxFileSize>100MB</maxFileSize> --> | |
| 55 | +<!-- </timeBasedFileNamingAndTriggeringPolicy> --> | |
| 56 | + </rollingPolicy> | |
| 57 | + <!-- 日志输出格式: --> | |
| 58 | + <layout class="ch.qos.logback.classic.PatternLayout"> | |
| 59 | + <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> | |
| 60 | + </layout> | |
| 61 | + </appender> | |
| 62 | + | |
| 63 | + <!-- | |
| 64 | + logger主要用于存放日志对象,也可以定义日志类型、级别 | |
| 65 | + name:表示匹配的logger类型前缀,也就是包的前半部分 | |
| 66 | + level:要记录的日志级别,包括 TRACE < DEBUG < INFO < WARN < ERROR | |
| 67 | + additivity:作用在于children-logger是否使用 rootLogger配置的appender进行输出, | |
| 68 | + false:表示只用当前logger的appender-ref,true: | |
| 69 | + 表示当前logger的appender-ref和rootLogger的appender-ref都有效 | |
| 70 | + --> | |
| 71 | + <!-- hibernate logger --> | |
| 72 | + <logger name="com.yuanqinnan" level="debug" /> | |
| 73 | + <!-- Spring framework logger --> | |
| 74 | + <logger name="org.springframework" level="debug" additivity="false"></logger> | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + <!-- | |
| 79 | + root与logger是父子关系,没有特别定义则默认为root,任何一个类只会和一个logger对应, | |
| 80 | + 要么是定义的logger,要么是root,判断的关键在于找到这个logger,然后判断这个logger的appender和level。 | |
| 81 | + --> | |
| 82 | + <root level="info"> | |
| 83 | + <appender-ref ref="stdout" /> | |
| 84 | + <appender-ref ref="appLogAppender" /> | |
| 85 | + </root> | |
| 86 | +</configuration> | |
| 0 | 87 | \ No newline at end of file | ... | ... |
src/main/resources/templates/logging/logging.html
0 → 100644
| 1 | +<!DOCTYPE> | |
| 2 | +<!--解决idea thymeleaf 表达式模板报红波浪线--> | |
| 3 | +<!--suppress ALL --> | |
| 4 | +<html xmlns:th="http://www.thymeleaf.org"> | |
| 5 | +<head> | |
| 6 | + <meta charset="UTF-8"> | |
| 7 | + <title>实时日志</title> | |
| 8 | + <!-- jquery --> | |
| 9 | + <script th:src="@{../../static/js/jquery.min.js}"></script> | |
| 10 | +<!-- <script src="../../static/js/jquery-1.9.1.min.js"></script> --> | |
| 11 | +</head> | |
| 12 | +<body> | |
| 13 | +<!-- 标题 --> | |
| 14 | +<h1 style="text-align: center;">实时日志</h1> | |
| 15 | + | |
| 16 | +<!-- 显示区 --> | |
| 17 | +<div id="loggingText" contenteditable="true" | |
| 18 | + style="width:100%;height: 600px;background-color: ghostwhite; overflow: auto;"></div> | |
| 19 | + | |
| 20 | +<!-- 操作栏 --> | |
| 21 | +<div style="text-align: center;"> | |
| 22 | + <button onclick="$('#loggingText').text('')" style="color: green; height: 35px;">清屏</button> | |
| 23 | + <button onclick="$('#loggingText').animate({scrollTop:$('#loggingText')[0].scrollHeight});" | |
| 24 | + style="color: green; height: 35px;">滚动至底部 | |
| 25 | + </button> | |
| 26 | + <button onclick="if(window.loggingAutoBottom){$(this).text('开启自动滚动');}else{$(this).text('关闭自动滚动');};window.loggingAutoBottom = !window.loggingAutoBottom" | |
| 27 | + style="color: green; height: 35px; ">开启自动滚动 | |
| 28 | + </button> | |
| 29 | +</div> | |
| 30 | +</body> | |
| 31 | +<script th:inline="javascript"> | |
| 32 | + //websocket对象 | |
| 33 | + let websocket = null; | |
| 34 | + var re=location.origin; | |
| 35 | + console.log(re); | |
| 36 | + //判断当前浏览器是否支持WebSocket | |
| 37 | + if ('WebSocket' in window) { | |
| 38 | + websocket = new WebSocket("ws://localhost:"+[[${port}]]+"/logging/websocket"); | |
| 39 | + } else { | |
| 40 | + console.error("不支持WebSocket"); | |
| 41 | + } | |
| 42 | + | |
| 43 | + //连接发生错误的回调方法 | |
| 44 | + websocket.onerror = function (e) { | |
| 45 | + console.error("WebSocket连接发生错误"); | |
| 46 | + }; | |
| 47 | + | |
| 48 | + //连接成功建立的回调方法 | |
| 49 | + websocket.onopen = function () { | |
| 50 | + console.log("WebSocket连接成功") | |
| 51 | + }; | |
| 52 | + | |
| 53 | + //接收到消息的回调方法 | |
| 54 | + websocket.onmessage = function (event) { | |
| 55 | + //追加 | |
| 56 | + if (event.data) { | |
| 57 | + | |
| 58 | + //日志内容 | |
| 59 | + let $loggingText = $("#loggingText"); | |
| 60 | + $loggingText.append(event.data); | |
| 61 | + | |
| 62 | + //是否开启自动底部 | |
| 63 | + if (window.loggingAutoBottom) { | |
| 64 | + //滚动条自动到最底部 | |
| 65 | + $loggingText.scrollTop($loggingText[0].scrollHeight); | |
| 66 | + } | |
| 67 | + } | |
| 68 | + } | |
| 69 | + | |
| 70 | + //连接关闭的回调方法 | |
| 71 | + websocket.onclose = function () { | |
| 72 | + console.log("WebSocket连接关闭") | |
| 73 | + }; | |
| 74 | +</script> | |
| 75 | +</html> | |
| 0 | 76 | \ No newline at end of file | ... | ... |