add:luence日志
This commit is contained in:
@@ -47,6 +47,11 @@
|
|||||||
<artifactId>hutool-all</artifactId>
|
<artifactId>hutool-all</artifactId>
|
||||||
<version>${hutool.version}</version>
|
<version>${hutool.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
<version>8.0.20</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- 日志链路追踪 https://tlog.yomahub.com/pages/f62a84/#%E5%90%8C%E6%AD%A5%E6%97%A5%E5%BF%97-->
|
<!-- 日志链路追踪 https://tlog.yomahub.com/pages/f62a84/#%E5%90%8C%E6%AD%A5%E6%97%A5%E5%BF%97-->
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -199,11 +204,6 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!--Mysql依赖包-->
|
<!--Mysql依赖包-->
|
||||||
<dependency>
|
|
||||||
<groupId>mysql</groupId>
|
|
||||||
<artifactId>mysql-connector-java</artifactId>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- druid数据源驱动 -->
|
<!-- druid数据源驱动 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019-2020 Zheng Jie
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.nl.common.aspect;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
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.nl.common.lucene.LuceneAppender;
|
||||||
|
import org.nl.common.utils.BaseCode;
|
||||||
|
import org.nl.common.utils.IPUtil;
|
||||||
|
import org.nl.common.utils.RequestHolder;
|
||||||
|
import org.nl.common.utils.SecurityUtils;
|
||||||
|
import org.nl.config.IdUtil;
|
||||||
|
import org.slf4j.MDC;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Parameter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Zheng Jie
|
||||||
|
* @date 2018-11-24
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Aspect
|
||||||
|
@Slf4j
|
||||||
|
public class LogAspect {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置环绕通知,使用在方法logPointcut()上注册的切入点
|
||||||
|
*
|
||||||
|
* @param joinPoint join point for advice
|
||||||
|
*/
|
||||||
|
@Around("@annotation(logInfo)")
|
||||||
|
public Object logAround(ProceedingJoinPoint joinPoint, org.nl.common.logging.annotation.Log logInfo) throws Throwable {
|
||||||
|
|
||||||
|
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||||
|
Method method = signature.getMethod();
|
||||||
|
String params = getParameter(method, joinPoint.getArgs());
|
||||||
|
HttpServletRequest request = RequestHolder.getHttpServletRequest();
|
||||||
|
String url = request.getRequestURI();
|
||||||
|
String requestIp = IPUtil.getIp(request);
|
||||||
|
MDC.put("requestMethod",url);
|
||||||
|
MDC.put("requestIp", requestIp);
|
||||||
|
MDC.put("requestTime", DateUtil.now());
|
||||||
|
LuceneAppender.traceIdTL.set(BaseCode.intToChars(IdUtil.getLongId()));
|
||||||
|
Object result = null;
|
||||||
|
long comming = System.currentTimeMillis();
|
||||||
|
try {
|
||||||
|
log.info("[--request--][请求接口:{}][请求参数:{}]",url,params);
|
||||||
|
result = joinPoint.proceed();
|
||||||
|
// //是否把日志存到日志表
|
||||||
|
// if (logInfo.isAddLogTable()) {
|
||||||
|
// Log log = new Log("INFO", System.currentTimeMillis() - comming);
|
||||||
|
// logService.save(getUsername(), StringUtils.getBrowser(request), requestIp, joinPoint, log);
|
||||||
|
// }
|
||||||
|
}catch (Exception ex){
|
||||||
|
|
||||||
|
StringBuffer errorStack = new StringBuffer();
|
||||||
|
errorStack.append("<br/>【异常堆栈:");
|
||||||
|
String errorMsg = ex.getMessage();
|
||||||
|
int x = 0;
|
||||||
|
StackTraceElement[] stackTrace = ex.getStackTrace();
|
||||||
|
if (stackTrace!=null && stackTrace.length>0){
|
||||||
|
for (StackTraceElement stack : stackTrace) {
|
||||||
|
x++;errorStack.append(stack.toString().replaceAll("<",">")).append("<br/>");
|
||||||
|
if (x>10){ break; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.error("[-requestError-][请求接口:{}]【异常信息:{}】[请求参数:{}] {}", url,errorMsg,params, errorStack.append("】").toString());
|
||||||
|
throw ex;
|
||||||
|
}finally {
|
||||||
|
log.info("[--response--][请求接口:{} 执行结束][耗时:{}s]",url,(System.currentTimeMillis() - comming)/1000);
|
||||||
|
MDC.clear();
|
||||||
|
LuceneAppender.traceIdTL.remove();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据方法和传入的参数获取请求参数
|
||||||
|
*/
|
||||||
|
private String getParameter(Method method, Object[] args) {
|
||||||
|
List<Object> argList = new ArrayList<>();
|
||||||
|
Parameter[] parameters = method.getParameters();
|
||||||
|
for (int i = 0; i < parameters.length; i++) {
|
||||||
|
//将RequestBody注解修饰的参数作为请求参数
|
||||||
|
RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class);
|
||||||
|
if (requestBody != null) {
|
||||||
|
argList.add(args[i]);
|
||||||
|
}
|
||||||
|
//将RequestParam注解修饰的参数作为请求参数
|
||||||
|
RequestParam requestParam = parameters[i].getAnnotation(RequestParam.class);
|
||||||
|
if (requestParam != null) {
|
||||||
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
String key = parameters[i].getName();
|
||||||
|
if (!StrUtil.isEmpty(requestParam.value())) {
|
||||||
|
key = requestParam.value();
|
||||||
|
}
|
||||||
|
map.put(key, args[i]);
|
||||||
|
argList.add(map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (argList.size() == 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return JSON.toJSONString(argList);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
try {
|
||||||
|
return SecurityUtils.getCurrentUsername();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package org.nl.common.lucene;
|
||||||
|
/**
|
||||||
|
* @author ldjun
|
||||||
|
* @version 1.0
|
||||||
|
* @date 2023年08月24日 13:00
|
||||||
|
* @desc desc
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
|
import com.yomahub.tlog.core.enhance.logback.async.AspectLogbackAsyncAppender;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.nl.common.lucene.remote.RemoteLogServer;
|
||||||
|
import org.slf4j.MDC;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class AsyncLuceneAppender extends AspectLogbackAsyncAppender {
|
||||||
|
|
||||||
|
|
||||||
|
public AsyncLuceneAppender() {
|
||||||
|
|
||||||
|
RemoteLogServer.asyncLuceneAppender = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void append(ILoggingEvent event) {
|
||||||
|
String traceId = LuceneAppender.traceIdTL.get();
|
||||||
|
if (StringUtils.isNotEmpty(traceId)){
|
||||||
|
MDC.put("traceId",traceId);
|
||||||
|
Map<String, String> mdcPropertyMap = event.getMDCPropertyMap();
|
||||||
|
if (mdcPropertyMap.getClass().getName().contains("SynchronizedMap")){
|
||||||
|
mdcPropertyMap.put("traceId",traceId);
|
||||||
|
}
|
||||||
|
MDC.clear();
|
||||||
|
}
|
||||||
|
RemoteLogServer.writeLog(event);
|
||||||
|
}
|
||||||
|
public void appendSync(ILoggingEvent event){
|
||||||
|
super.append(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package org.nl.common.lucene;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: lyd
|
||||||
|
* @Description: 定义lucene相关常量
|
||||||
|
* @Date: 2023/8/25
|
||||||
|
*/
|
||||||
|
public class LogMessageConstant {
|
||||||
|
/** */
|
||||||
|
public final static String SORT_NAME = "time";
|
||||||
|
/** 级别 */
|
||||||
|
public final static String FIELD_LEVEL = "level";
|
||||||
|
/** 时间 */
|
||||||
|
public final static String FIELD_TIMESTAMP = "timestamp";
|
||||||
|
/** 类的限定名 */
|
||||||
|
public final static String FIELD_CLASS_NAME = "logger";
|
||||||
|
/** 线程名 */
|
||||||
|
public final static String FIELD_THREAD = "thread";
|
||||||
|
/** 日志内容 */
|
||||||
|
public final static String FIELD_MESSAGE = "message";
|
||||||
|
public final static String FIELD_TRACEID = "tlogTraceId";
|
||||||
|
// 定义颜色值
|
||||||
|
/** 文本颜色:黑色 */
|
||||||
|
public final static String COLOR_BLACK = "\u001B[30m";
|
||||||
|
/** 文本颜色:红色 */
|
||||||
|
public final static String COLOR_RED = "\u001B[31m";
|
||||||
|
/** 文本颜色:绿色 */
|
||||||
|
public final static String COLOR_GREEN = "\u001B[32m";
|
||||||
|
/** 文本颜色:黄色 */
|
||||||
|
public final static String COLOR_YELLOW = "\u001B[33m";
|
||||||
|
/** 文本颜色:蓝色 */
|
||||||
|
public final static String COLOR_BLUE = "\u001B[34m";
|
||||||
|
/** 文本颜色:品红色 */
|
||||||
|
public final static String COLOR_MAGENTA = "\u001B[35m";
|
||||||
|
/** 文本颜色:青色 */
|
||||||
|
public final static String COLOR_CYAN = "\u001B[36m";
|
||||||
|
/** 文本颜色:白色 */
|
||||||
|
public final static String COLOR_WHITE = "\u001B[37m";
|
||||||
|
/** 文本颜色重置 */
|
||||||
|
public final static String COLOR_RESET = "\u001B[0m";
|
||||||
|
/** 背景颜色:黄色 */
|
||||||
|
public final static String BACKGROUND_YELLOW = "\u001B[43m";
|
||||||
|
/** 索引路径 */
|
||||||
|
public final static String INDEX_DIR = "E:\\lucene\\index";
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
package org.nl.common.lucene;
|
||||||
|
/**
|
||||||
|
* @author ldjun
|
||||||
|
* @version 1.0
|
||||||
|
* @date 2023年08月24日 13:00
|
||||||
|
* @desc desc
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
|
import ch.qos.logback.core.AppenderBase;
|
||||||
|
import com.alibaba.ttl.TransmittableThreadLocal;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.lucene.analysis.Analyzer;
|
||||||
|
import org.apache.lucene.document.*;
|
||||||
|
import org.apache.lucene.index.IndexWriter;
|
||||||
|
import org.apache.lucene.index.IndexWriterConfig;
|
||||||
|
import org.apache.lucene.store.Directory;
|
||||||
|
import org.apache.lucene.store.FSDirectory;
|
||||||
|
import org.wltea.analyzer.lucene.IKAnalyzer;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
public class LuceneAppender extends AppenderBase<ILoggingEvent> {
|
||||||
|
|
||||||
|
public static final TransmittableThreadLocal<String> traceIdTL = new TransmittableThreadLocal();
|
||||||
|
public LuceneProperties properties;
|
||||||
|
public static Directory index;
|
||||||
|
private List<LucenePropertyAndEncoder> encoders;
|
||||||
|
public static IndexWriter indexWriter;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
super.start();
|
||||||
|
try {
|
||||||
|
// 读取配置文件
|
||||||
|
Properties properties = YmlConfigFileUtil.readConfig("config/application.yml");
|
||||||
|
|
||||||
|
// 获取配置值
|
||||||
|
String luceneDir = properties.getProperty("lucene.index.path");
|
||||||
|
System.out.println("---index地址----"+luceneDir);
|
||||||
|
index = FSDirectory.open(Paths.get(luceneDir));
|
||||||
|
// 初始化 Lucene 索引
|
||||||
|
Analyzer analyzer = new IKAnalyzer();
|
||||||
|
IndexWriterConfig config = new IndexWriterConfig(analyzer);
|
||||||
|
indexWriter = new IndexWriter(index, config);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void append(ILoggingEvent event) {
|
||||||
|
Document doc = new Document();
|
||||||
|
for (Property property : this.properties.getProperties()) {
|
||||||
|
LucenePropertyAndEncoder encoder = new LucenePropertyAndEncoder(property, this.context);
|
||||||
|
String encode = encoder.encode(event);
|
||||||
|
doc.add(new StringField(property.getName(), encode, Field.Store.YES));
|
||||||
|
}
|
||||||
|
Map<String, String> map = event.getMDCPropertyMap();
|
||||||
|
if (!map.isEmpty() && StringUtils.isNotEmpty(map.get("traceId"))){
|
||||||
|
doc.add(new StringField("traceId",map.get("traceId"), Field.Store.YES));
|
||||||
|
}else {
|
||||||
|
doc.add(new StringField("traceId"," ", Field.Store.YES));
|
||||||
|
}
|
||||||
|
|
||||||
|
doc.add(new TextField(LogMessageConstant.FIELD_MESSAGE, event.getFormattedMessage(), Field.Store.YES));
|
||||||
|
doc.add(new StringField(LogMessageConstant.FIELD_TIMESTAMP, String.valueOf(event.getTimeStamp()),Field.Store.YES));
|
||||||
|
doc.add(new NumericDocValuesField(LogMessageConstant.SORT_NAME, event.getTimeStamp()));
|
||||||
|
try {
|
||||||
|
indexWriter.addDocument(doc);
|
||||||
|
indexWriter.commit();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
super.stop();
|
||||||
|
try {
|
||||||
|
indexWriter.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProperties(LuceneProperties properties) {
|
||||||
|
this.properties = properties;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package org.nl.common.lucene;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class LuceneProperties {
|
||||||
|
|
||||||
|
private List<Property> properties;
|
||||||
|
|
||||||
|
public LuceneProperties() {
|
||||||
|
this.properties = new ArrayList<Property>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Property> getProperties() {
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addProperty(Property property) {
|
||||||
|
properties.add(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package org.nl.common.lucene;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.PatternLayout;
|
||||||
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
|
import ch.qos.logback.core.Context;
|
||||||
|
import ch.qos.logback.core.pattern.PatternLayoutBase;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @author ZZQ
|
||||||
|
* @Date 2023/12/22 18:11
|
||||||
|
*/
|
||||||
|
public class LucenePropertyAndEncoder {
|
||||||
|
|
||||||
|
private Property property;
|
||||||
|
|
||||||
|
private PatternLayoutBase layout = new PatternLayout();
|
||||||
|
|
||||||
|
public LucenePropertyAndEncoder(Property property, Context context) {
|
||||||
|
this.property = property;
|
||||||
|
this.layout.setContext(context);
|
||||||
|
this.layout.setPattern(String.valueOf(property.getValue()));
|
||||||
|
this.layout.setPostCompileProcessor(null);
|
||||||
|
this.layout.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String encode(ILoggingEvent event) {
|
||||||
|
return layout.doLayout(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return property.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean allowEmpty() {
|
||||||
|
return property.isAllowEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package org.nl.common.lucene;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @author ZZQ
|
||||||
|
* @Date 2023/12/26 15:30
|
||||||
|
*/
|
||||||
|
public class Property {
|
||||||
|
private String name;
|
||||||
|
private String value;
|
||||||
|
private boolean allowEmpty;
|
||||||
|
|
||||||
|
public Property() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Property(String name, String value, boolean allowEmpty) {
|
||||||
|
this.name = name;
|
||||||
|
this.value = value;
|
||||||
|
this.allowEmpty = allowEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAllowEmpty() {
|
||||||
|
return allowEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAllowEmpty(boolean allowEmpty) {
|
||||||
|
this.allowEmpty = allowEmpty;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package org.nl.common.lucene;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: lyd
|
||||||
|
* @Description: 配置文件获取方法
|
||||||
|
* @Date: 2023/12/6
|
||||||
|
*/
|
||||||
|
public class YmlConfigFileUtil {
|
||||||
|
public static Properties readConfig(String configFile) {
|
||||||
|
// 创建 Resource 对象
|
||||||
|
Resource resource = new ClassPathResource(configFile);
|
||||||
|
|
||||||
|
// 创建 YamlPropertiesFactoryBean
|
||||||
|
YamlPropertiesFactoryBean yamlPropertiesFactoryBean = new YamlPropertiesFactoryBean();
|
||||||
|
yamlPropertiesFactoryBean.setResources(resource);
|
||||||
|
|
||||||
|
// 获取 Properties 对象
|
||||||
|
Properties properties = yamlPropertiesFactoryBean.getObject();
|
||||||
|
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package org.nl.common.lucene.remote;
|
||||||
|
|
||||||
|
import io.netty.bootstrap.AbstractBootstrap;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @author ZZQ
|
||||||
|
* @Date 2024/1/22 10:01
|
||||||
|
*/
|
||||||
|
public abstract class AbstraceServer {
|
||||||
|
|
||||||
|
|
||||||
|
public AbstraceServer(SocketAddress address) {
|
||||||
|
this.address = address;
|
||||||
|
if (channel!=null){
|
||||||
|
doDestroy();
|
||||||
|
}
|
||||||
|
doOpen();
|
||||||
|
doConnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractBootstrap server;
|
||||||
|
public SocketAddress address;
|
||||||
|
public Channel channel;
|
||||||
|
|
||||||
|
public abstract void doOpen();
|
||||||
|
|
||||||
|
public void doDestroy(){
|
||||||
|
if (channel!=null){
|
||||||
|
channel.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public abstract void doConnect() ;
|
||||||
|
|
||||||
|
public void doDisConnect(){
|
||||||
|
if (channel!=null){
|
||||||
|
channel.close();
|
||||||
|
channel.flush();
|
||||||
|
doConnect();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
package org.nl.common.lucene.remote;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import io.netty.util.CharsetUtil;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.nl.common.lucene.AsyncLuceneAppender;
|
||||||
|
import org.nl.common.lucene.remote.impl.ClientServer;
|
||||||
|
import org.nl.common.lucene.remote.impl.RemoteServer;
|
||||||
|
import org.nl.common.utils.MapOf;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.SmartLifecycle;
|
||||||
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
|
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @author ZZQ
|
||||||
|
* @Date 2024/1/22 09:06
|
||||||
|
*/
|
||||||
|
//@Component
|
||||||
|
public class RemoteLogServer implements SmartLifecycle {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private StringRedisTemplate redisTemplate;
|
||||||
|
|
||||||
|
public static volatile Boolean LOCAL_LOG = Boolean.TRUE;
|
||||||
|
|
||||||
|
private Integer port = 20888;
|
||||||
|
|
||||||
|
public static AbstraceServer server;
|
||||||
|
|
||||||
|
public static AsyncLuceneAppender asyncLuceneAppender;
|
||||||
|
|
||||||
|
public static void writeLog(ILoggingEvent event){
|
||||||
|
if (LOCAL_LOG){
|
||||||
|
asyncLuceneAppender.appendSync(event);
|
||||||
|
}else {
|
||||||
|
ByteBuf log = Unpooled.copiedBuffer(JSON.toJSONString(event), CharsetUtil.UTF_8);
|
||||||
|
server.channel.writeAndFlush(log);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
try {
|
||||||
|
String provider = redisTemplate.opsForValue().get("providers");
|
||||||
|
if (StringUtils.isEmpty(provider)){
|
||||||
|
String ip = Inet4Address.getLocalHost().getHostAddress();
|
||||||
|
Map<String,Object> config = MapOf.of("ip", ip, "port", port);
|
||||||
|
redisTemplate.opsForValue().set("provider", JSON.toJSONString(config));
|
||||||
|
Runtime.getRuntime().addShutdownHook(new Thread(() ->{
|
||||||
|
System.out.println("------服务关闭-升级从变主-------");
|
||||||
|
server.doDestroy();
|
||||||
|
redisTemplate.delete("providers");
|
||||||
|
try {
|
||||||
|
Thread.sleep(5000);
|
||||||
|
}catch (Exception ex){}
|
||||||
|
}));
|
||||||
|
server = new RemoteServer(new InetSocketAddress(ip, port));
|
||||||
|
LOCAL_LOG =Boolean.TRUE;
|
||||||
|
}else {
|
||||||
|
Map<String,String> map = JSONObject.parseObject(provider, HashMap.class);
|
||||||
|
String ip = map.get("ip");
|
||||||
|
Integer port = Integer.valueOf(map.get("port"));
|
||||||
|
server = new ClientServer(new InetSocketAddress(ip, port));
|
||||||
|
LOCAL_LOG = Boolean.FALSE;
|
||||||
|
}
|
||||||
|
}catch (Exception ex){
|
||||||
|
ex.printStackTrace();
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRunning() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package org.nl.common.lucene.remote.coder;
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||||
|
import io.netty.handler.timeout.IdleStateEvent;
|
||||||
|
import org.nl.common.lucene.remote.RemoteLogServer;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @author ZZQ
|
||||||
|
* @Date 2024/1/22 10:24
|
||||||
|
*/
|
||||||
|
public class LogConsumerHandler extends ChannelInboundHandlerAdapter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
System.out.println("断开连接---");
|
||||||
|
RemoteLogServer.LOCAL_LOG = Boolean.TRUE;
|
||||||
|
RemoteLogServer.server.doDestroy();
|
||||||
|
//重新建立
|
||||||
|
super.channelInactive(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
System.out.println("连接");
|
||||||
|
super.channelActive(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||||
|
System.out.println("接收到消息");
|
||||||
|
super.channelRead(ctx, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
|
||||||
|
if (evt instanceof IdleStateEvent){
|
||||||
|
IdleStateEvent stateEvent = (IdleStateEvent) evt;
|
||||||
|
System.out.println(stateEvent.state());
|
||||||
|
}
|
||||||
|
super.userEventTriggered(ctx, evt);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package org.nl.common.lucene.remote.coder;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.spi.LoggingEvent;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
|
import org.nl.common.lucene.remote.RemoteLogServer;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @author ZZQ
|
||||||
|
* @Date 2024/1/22 10:24
|
||||||
|
*/
|
||||||
|
public class LogProviderHandler extends SimpleChannelInboundHandler<String> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
System.out.println("断开连接---");
|
||||||
|
super.channelInactive(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void channelRead0(ChannelHandlerContext ctx, String c){
|
||||||
|
LoggingEvent event = JSONObject.parseObject(c, LoggingEvent.class);
|
||||||
|
RemoteLogServer.asyncLuceneAppender.appendSync(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
System.out.println("创建了连接----");
|
||||||
|
super.channelActive(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package org.nl.common.lucene.remote.impl;
|
||||||
|
|
||||||
|
import io.netty.bootstrap.Bootstrap;
|
||||||
|
import io.netty.buffer.PooledByteBufAllocator;
|
||||||
|
import io.netty.channel.ChannelFuture;
|
||||||
|
import io.netty.channel.ChannelInitializer;
|
||||||
|
import io.netty.channel.ChannelOption;
|
||||||
|
import io.netty.channel.EventLoopGroup;
|
||||||
|
import io.netty.channel.nio.NioEventLoopGroup;
|
||||||
|
import io.netty.channel.socket.SocketChannel;
|
||||||
|
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||||
|
import io.netty.handler.codec.LengthFieldPrepender;
|
||||||
|
import io.netty.handler.timeout.IdleStateHandler;
|
||||||
|
import io.netty.util.concurrent.Future;
|
||||||
|
import org.nl.common.lucene.remote.AbstraceServer;
|
||||||
|
import org.nl.common.lucene.remote.coder.LogConsumerHandler;
|
||||||
|
|
||||||
|
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
|
||||||
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @author ZZQ
|
||||||
|
* @Date 2024/1/22 10:01
|
||||||
|
*/
|
||||||
|
public class ClientServer extends AbstraceServer {
|
||||||
|
|
||||||
|
private static EventLoopGroup group = new NioEventLoopGroup();
|
||||||
|
|
||||||
|
public ClientServer(SocketAddress address) {
|
||||||
|
super(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 非阻塞IO线程组
|
||||||
|
@Override
|
||||||
|
public void doOpen() {
|
||||||
|
server = new Bootstrap();
|
||||||
|
server.group(group)
|
||||||
|
.option(ChannelOption.SO_KEEPALIVE, true)
|
||||||
|
.option(ChannelOption.TCP_NODELAY, true)
|
||||||
|
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
|
||||||
|
.channel(NioSocketChannel.class);
|
||||||
|
|
||||||
|
server.handler(new ChannelInitializer<SocketChannel>() {
|
||||||
|
@Override
|
||||||
|
protected void initChannel(SocketChannel ch) throws Exception {
|
||||||
|
ch.pipeline()
|
||||||
|
.addLast("client-idle-handler", new IdleStateHandler(500, 0,0 , MILLISECONDS))
|
||||||
|
.addLast(new LengthFieldPrepender(2))
|
||||||
|
.addLast( new LogConsumerHandler());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doDestroy() {
|
||||||
|
super.doDestroy();
|
||||||
|
Future<?> bossGroupShutdownFuture = group.shutdownGracefully();
|
||||||
|
bossGroupShutdownFuture.syncUninterruptibly();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doConnect() {
|
||||||
|
try {
|
||||||
|
ChannelFuture connect = ((Bootstrap) server).connect(address);
|
||||||
|
connect.syncUninterruptibly();
|
||||||
|
channel = connect.channel();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
this.doDestroy();
|
||||||
|
throw t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package org.nl.common.lucene.remote.impl;
|
||||||
|
|
||||||
|
import io.netty.bootstrap.ServerBootstrap;
|
||||||
|
import io.netty.buffer.PooledByteBufAllocator;
|
||||||
|
import io.netty.channel.*;
|
||||||
|
import io.netty.channel.nio.NioEventLoopGroup;
|
||||||
|
import io.netty.channel.socket.SocketChannel;
|
||||||
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||||
|
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
|
||||||
|
import io.netty.handler.codec.LengthFieldPrepender;
|
||||||
|
import io.netty.handler.codec.string.StringDecoder;
|
||||||
|
import io.netty.handler.timeout.IdleStateHandler;
|
||||||
|
import io.netty.util.concurrent.Future;
|
||||||
|
import org.nl.common.lucene.remote.AbstraceServer;
|
||||||
|
import org.nl.common.lucene.remote.coder.LogProviderHandler;
|
||||||
|
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
|
||||||
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @author ZZQ
|
||||||
|
* @Date 2024/1/22 10:01
|
||||||
|
*/
|
||||||
|
public class RemoteServer extends AbstraceServer {
|
||||||
|
|
||||||
|
private static EventLoopGroup boss = new NioEventLoopGroup();
|
||||||
|
private static EventLoopGroup worker = new NioEventLoopGroup();
|
||||||
|
|
||||||
|
public RemoteServer(SocketAddress address) {
|
||||||
|
super(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 非阻塞IO线程组
|
||||||
|
@Override
|
||||||
|
public void doOpen() {
|
||||||
|
ServerBootstrap bootstrap = new ServerBootstrap();
|
||||||
|
bootstrap
|
||||||
|
.group(boss, worker)
|
||||||
|
.channel(NioServerSocketChannel.class)
|
||||||
|
.option(ChannelOption.SO_REUSEADDR, Boolean.TRUE)
|
||||||
|
.childOption(ChannelOption.TCP_NODELAY, Boolean.TRUE)
|
||||||
|
.childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE)
|
||||||
|
.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
|
||||||
|
.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||||
|
@Override
|
||||||
|
protected void initChannel(SocketChannel ch) throws Exception {
|
||||||
|
ch.pipeline()
|
||||||
|
.addLast("client-idle-handler", new IdleStateHandler(500, 0, 0, MILLISECONDS))
|
||||||
|
.addLast(new LengthFieldBasedFrameDecoder(8089, 0, 2, 0, 2))
|
||||||
|
.addLast(new LengthFieldPrepender(2))
|
||||||
|
.addLast("encode",new StringDecoder())
|
||||||
|
.addLast(new LogProviderHandler());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
server = bootstrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doDestroy(){
|
||||||
|
Future<?> bossGroupShutdownFuture = boss.shutdownGracefully();
|
||||||
|
Future<?> workerGroupShutdownFuture = worker.shutdownGracefully();
|
||||||
|
bossGroupShutdownFuture.syncUninterruptibly();
|
||||||
|
workerGroupShutdownFuture.syncUninterruptibly();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doConnect() {
|
||||||
|
ChannelFuture future = server.bind(address);
|
||||||
|
boolean ret = future.awaitUninterruptibly(3000, MILLISECONDS);
|
||||||
|
if (ret && future.isSuccess()) {
|
||||||
|
Channel newChannel = future.channel();
|
||||||
|
if (channel != null) {
|
||||||
|
channel.close();
|
||||||
|
channel = newChannel;
|
||||||
|
}
|
||||||
|
} else if (future.cause() != null) {
|
||||||
|
Throwable cause = future.cause();
|
||||||
|
cause.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package org.nl.common.utils;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @author ZZQ
|
||||||
|
* @Date 2023/2/9 2:54 下午
|
||||||
|
*/
|
||||||
|
public class BaseCode {
|
||||||
|
|
||||||
|
static final char[] MySerials = new char[]{
|
||||||
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||||
|
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
|
||||||
|
'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p','q','r','s','t','u','v','w','x','y','z',
|
||||||
|
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
||||||
|
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P','Q','R','S','T','U','V','W','X','Y','Z'};
|
||||||
|
|
||||||
|
|
||||||
|
public static final String intToChars(long n){
|
||||||
|
String s = "";
|
||||||
|
if (n == 0) {
|
||||||
|
s = "0";
|
||||||
|
}
|
||||||
|
while (n != 0) {
|
||||||
|
int i = (int) (n % MySerials.length);
|
||||||
|
char c = MySerials[i];
|
||||||
|
s = c + s;
|
||||||
|
n = n / MySerials.length;
|
||||||
|
}
|
||||||
|
for (int x = s.length();x<5;x++){
|
||||||
|
s="0"+s;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019-2020 Zheng Jie
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.nl.common.utils;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.NetworkInterface;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Zheng Jie
|
||||||
|
* 字符串工具类, 继承org.apache.commons.lang3.StringUtils类
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class IPUtil {
|
||||||
|
|
||||||
|
public static String IP = null;
|
||||||
|
/**
|
||||||
|
* 获取当前机器的IP
|
||||||
|
*
|
||||||
|
* @return /
|
||||||
|
*/
|
||||||
|
public static String getLocalIp() {
|
||||||
|
if (IP!=null){
|
||||||
|
return IP;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
InetAddress candidateAddress = null;
|
||||||
|
// 遍历所有的网络接口
|
||||||
|
for (Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); interfaces.hasMoreElements();) {
|
||||||
|
NetworkInterface anInterface = interfaces.nextElement();
|
||||||
|
// 在所有的接口下再遍历IP
|
||||||
|
for (Enumeration<InetAddress> inetAddresses = anInterface.getInetAddresses(); inetAddresses.hasMoreElements();) {
|
||||||
|
InetAddress inetAddr = inetAddresses.nextElement();
|
||||||
|
// 排除loopback类型地址
|
||||||
|
if (!inetAddr.isLoopbackAddress()) {
|
||||||
|
if (inetAddr.isSiteLocalAddress()) {
|
||||||
|
// 如果是site-local地址,就是它了
|
||||||
|
return inetAddr.getHostAddress();
|
||||||
|
} else if (candidateAddress == null) {
|
||||||
|
// site-local类型的地址未被发现,先记录候选地址
|
||||||
|
candidateAddress = inetAddr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (candidateAddress != null) {
|
||||||
|
return candidateAddress.getHostAddress();
|
||||||
|
}
|
||||||
|
// 如果没有发现 non-loopback地址.只能用最次选的方案
|
||||||
|
InetAddress jdkSuppliedAddress = InetAddress.getLocalHost();
|
||||||
|
if (jdkSuppliedAddress == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
IP = jdkSuppliedAddress.getHostAddress();
|
||||||
|
return jdkSuppliedAddress.getHostAddress();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static String getIp(HttpServletRequest request) {
|
||||||
|
String ip = request.getHeader("X-Forwarded-For");
|
||||||
|
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||||
|
ip = request.getHeader("Proxy-Client-IP");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||||
|
ip = request.getHeader("WL-Proxy-Client-IP");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||||
|
ip = request.getRemoteAddr();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ip != null && ip.contains(",")) {
|
||||||
|
String[] ipArray = ip.split(",");
|
||||||
|
ip = ipArray[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
package org.nl.config;
|
||||||
|
|
||||||
|
import com.alibaba.druid.filter.FilterChain;
|
||||||
|
import com.alibaba.druid.filter.FilterEventAdapter;
|
||||||
|
import com.alibaba.druid.proxy.jdbc.JdbcParameter;
|
||||||
|
import com.alibaba.druid.proxy.jdbc.PreparedStatementProxy;
|
||||||
|
import com.alibaba.druid.proxy.jdbc.ResultSetProxy;
|
||||||
|
import com.alibaba.druid.proxy.jdbc.StatementProxy;
|
||||||
|
import com.alibaba.druid.sql.SQLUtils;
|
||||||
|
import com.alibaba.druid.util.JdbcUtils;
|
||||||
|
import com.mysql.cj.jdbc.result.ResultSetImpl;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @author ZZQ
|
||||||
|
* @Date 2023/2/10 11:27 上午
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class DruidFilter extends FilterEventAdapter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int preparedStatement_executeUpdate(FilterChain chain, PreparedStatementProxy statement) throws SQLException {
|
||||||
|
|
||||||
|
return super.preparedStatement_executeUpdate(chain, statement);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql) throws SQLException {
|
||||||
|
|
||||||
|
return super.statement_executeUpdate(chain, statement, sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void statementExecuteAfter(StatementProxy statement, String sql, boolean result) {
|
||||||
|
int size = statement.getParametersSize();
|
||||||
|
String executeSql = sql;
|
||||||
|
int count = 0;
|
||||||
|
try {
|
||||||
|
count=statement.getUpdateCount();
|
||||||
|
}catch (Exception ex){ }
|
||||||
|
if (count>0) {
|
||||||
|
if (size > 0) {
|
||||||
|
Collection<JdbcParameter> values = statement.getParameters().values();
|
||||||
|
List<Object> params = new ArrayList<>();
|
||||||
|
for (JdbcParameter value : values) {
|
||||||
|
params.add(value.getValue());
|
||||||
|
}
|
||||||
|
executeSql = SQLUtils.format(executeSql, JdbcUtils.MYSQL, params);
|
||||||
|
}
|
||||||
|
log.info("[----SQL----][update][ SQL: {} ]", executeSql);
|
||||||
|
}
|
||||||
|
super.statementExecuteAfter(statement, sql, result);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public ResultSetProxy statement_getResultSet(FilterChain chain, StatementProxy statement) throws SQLException {
|
||||||
|
ResultSetProxy rs = super.statement_getResultSet(chain, statement);
|
||||||
|
String executeSql = statement.getLastExecuteSql();
|
||||||
|
if (true){
|
||||||
|
int result = 0;
|
||||||
|
if (rs != null) {
|
||||||
|
ResultSetImpl rss = rs.getResultSetRaw().unwrap(ResultSetImpl.class);
|
||||||
|
result = rss.getRows().size();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
int size = statement.getParametersSize();
|
||||||
|
if (size>0){
|
||||||
|
Collection<JdbcParameter> values = statement.getParameters().values();
|
||||||
|
List<Object> params = new ArrayList<>();
|
||||||
|
for (JdbcParameter value : values) {
|
||||||
|
params.add(value.getValue());
|
||||||
|
}
|
||||||
|
executeSql = SQLUtils.format(executeSql, JdbcUtils.MYSQL, params);
|
||||||
|
}
|
||||||
|
}catch (Exception ex){
|
||||||
|
log.warn("[-SQL解析异常-][{}]",ex.getMessage());
|
||||||
|
}
|
||||||
|
log.info("[----SQL----][select][执行结果:{}][ SQL: {} ]",result, executeSql);
|
||||||
|
}
|
||||||
|
return rs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package org.nl.system.logserver;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.annotation.SaIgnore;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.nl.common.logging.annotation.Log;
|
||||||
|
import org.nl.system.service.logserver.LogQuery;
|
||||||
|
import org.nl.system.service.logserver.LuceneLogService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ldjun
|
||||||
|
* @version 1.0
|
||||||
|
* @date 2023年01月29日 18:55
|
||||||
|
* @desc desc
|
||||||
|
*/
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/esLog")
|
||||||
|
@Slf4j
|
||||||
|
public class LuceneLogController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private LuceneLogService luceneLogService;
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/labels/{type}")
|
||||||
|
//("获取标签")
|
||||||
|
public ResponseEntity<Object> labelsValues(@PathVariable String type) {
|
||||||
|
return new ResponseEntity<>(luceneLogService.getLabelsValues(type), HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/query")
|
||||||
|
//("日志查询")
|
||||||
|
public ResponseEntity<Object> queryAll(@RequestBody LogQuery query) {
|
||||||
|
return new ResponseEntity<>(luceneLogService.query(query), HttpStatus.OK);
|
||||||
|
}
|
||||||
|
@DeleteMapping("/clearLogs")
|
||||||
|
//("清空日志")
|
||||||
|
public ResponseEntity<Object> clearLogs(@RequestBody LogQuery query) {
|
||||||
|
luceneLogService.clearLogs(query);
|
||||||
|
return new ResponseEntity<>(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/thread")
|
||||||
|
@SaIgnore
|
||||||
|
@Log("线程追踪测试")
|
||||||
|
//("清空日志")
|
||||||
|
public ResponseEntity<Object> thread(@RequestBody LogQuery query) {
|
||||||
|
log.info("线程链路测试"+Thread.currentThread().getName());
|
||||||
|
log.error("线程链路测试"+Thread.currentThread().getName());
|
||||||
|
luceneLogService.syncdemo();
|
||||||
|
Thread thread = new Thread(()->{
|
||||||
|
try {
|
||||||
|
Thread.sleep(5000);
|
||||||
|
log.info("线程链路测试"+Thread.currentThread().getName());
|
||||||
|
log.error("线程链路测试"+Thread.currentThread().getName());
|
||||||
|
log.info("线程链路测试"+Thread.currentThread().getName());
|
||||||
|
}catch (Exception ex){
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
thread.start();
|
||||||
|
return new ResponseEntity<>(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package org.nl.system.service.logserver;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @author ZZQ
|
||||||
|
* @Date 2023/2/8 5:18 下午
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class LogQuery {
|
||||||
|
/**
|
||||||
|
* 创建时间范围查询
|
||||||
|
*/
|
||||||
|
private Date startTime;
|
||||||
|
private Date endTime;
|
||||||
|
/**
|
||||||
|
* 追踪id
|
||||||
|
*/
|
||||||
|
private String traceId;
|
||||||
|
private String requestMethod;
|
||||||
|
/**
|
||||||
|
* 日志内容模糊匹配
|
||||||
|
*/
|
||||||
|
private String message;
|
||||||
|
/**
|
||||||
|
* 日志级别
|
||||||
|
*/
|
||||||
|
private String logLevel;
|
||||||
|
/**
|
||||||
|
* 系统标签
|
||||||
|
*/
|
||||||
|
private String system;
|
||||||
|
/**
|
||||||
|
* 是否只查询Http相关请求
|
||||||
|
*/
|
||||||
|
private Boolean isRequest = Boolean.TRUE;
|
||||||
|
/**
|
||||||
|
* 是否过滤wql日志
|
||||||
|
*/
|
||||||
|
private Boolean filterSql = Boolean.TRUE;
|
||||||
|
|
||||||
|
private Integer size = 20;
|
||||||
|
|
||||||
|
private Integer page = 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package org.nl.system.service.logserver;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @author ZZQ
|
||||||
|
* @Date 2023/2/8 4:06 下午
|
||||||
|
*/
|
||||||
|
//@Document(indexName = "#{@ESConfig.index}", type = "mes_log")
|
||||||
|
@Data
|
||||||
|
public class LogRepositoryDTO {
|
||||||
|
|
||||||
|
private String message;
|
||||||
|
private String host;
|
||||||
|
private String logLevel;
|
||||||
|
private String logger;
|
||||||
|
private String requestTime;
|
||||||
|
private String requestIp;
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
private String traceId;
|
||||||
|
private String requestMethod;
|
||||||
|
private String thread;
|
||||||
|
private String system;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package org.nl.system.service.logserver;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ldjun
|
||||||
|
* @version 1.0
|
||||||
|
* @date 2023年02月07日 14:34
|
||||||
|
* @desc desc
|
||||||
|
*/
|
||||||
|
public interface LuceneLogService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空日志
|
||||||
|
*/
|
||||||
|
void clearLogs(LogQuery query);
|
||||||
|
/**
|
||||||
|
* 获取labels和values树
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
JSONArray getLabelsValues(String type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日志查询
|
||||||
|
* @param logQuery
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
JSONObject query(LogQuery logQuery);
|
||||||
|
|
||||||
|
void syncdemo();
|
||||||
|
}
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
package org.nl.system.service.logserver;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateField;
|
||||||
|
import cn.hutool.core.date.DateTime;
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.db.PageResult;
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.lucene.document.Document;
|
||||||
|
import org.apache.lucene.index.DirectoryReader;
|
||||||
|
import org.apache.lucene.index.IndexWriter;
|
||||||
|
import org.apache.lucene.index.Term;
|
||||||
|
import org.apache.lucene.queryparser.classic.QueryParser;
|
||||||
|
import org.apache.lucene.search.*;
|
||||||
|
import org.apache.lucene.store.FSDirectory;
|
||||||
|
import org.apache.lucene.util.BytesRef;
|
||||||
|
import org.nl.common.exception.BadRequestException;
|
||||||
|
import org.nl.common.lucene.LuceneAppender;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.wltea.analyzer.lucene.IKAnalyzer;
|
||||||
|
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class LuceneLogServiceImpl implements LuceneLogService {
|
||||||
|
|
||||||
|
static String[] INFO_LEVEL = new String[]{"DEBUG","INFO","WARN","ERROR"};
|
||||||
|
|
||||||
|
@Value("${lucene.index.path}")
|
||||||
|
private String indexUrl;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearLogs(LogQuery query) {
|
||||||
|
try {
|
||||||
|
IndexWriter indexWriter = LuceneAppender.indexWriter;
|
||||||
|
if (indexWriter != null){
|
||||||
|
BooleanQuery.Builder booleanQueryBuilder = new BooleanQuery.Builder();
|
||||||
|
DateTime offset = DateUtil.offset(new Date(), DateField.HOUR_OF_DAY, -10);
|
||||||
|
TermRangeQuery termRangeQuery = new TermRangeQuery(
|
||||||
|
"requestTime",null,
|
||||||
|
new BytesRef(DateUtil.format(offset, "yyyy-MM-dd HH:mm:ss.SSS")), true, true);
|
||||||
|
booleanQueryBuilder.add(termRangeQuery,BooleanClause.Occur.MUST);
|
||||||
|
indexWriter.deleteDocuments(termRangeQuery);
|
||||||
|
indexWriter.commit();
|
||||||
|
}
|
||||||
|
}catch (Exception ex){
|
||||||
|
throw new BadRequestException("删除失败:"+ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONArray getLabelsValues(String type) {
|
||||||
|
JSONArray result = new JSONArray();
|
||||||
|
for (String v : INFO_LEVEL) {
|
||||||
|
JSONObject item = new JSONObject();
|
||||||
|
item.put("label", v);
|
||||||
|
item.put("value", v);
|
||||||
|
result.add(item);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject query(LogQuery logQuery) {
|
||||||
|
JSONObject res = new JSONObject();
|
||||||
|
PageResult page = new PageResult();
|
||||||
|
page.setPage(logQuery.getPage());
|
||||||
|
page.setPageSize(logQuery.getSize());
|
||||||
|
try {
|
||||||
|
FSDirectory directory = FSDirectory.open(Paths.get(indexUrl));
|
||||||
|
DirectoryReader open = DirectoryReader.open(directory);
|
||||||
|
IndexSearcher searcher = new IndexSearcher(open);
|
||||||
|
// 创建排序对象,需要排序字段SortField,参数:字段的名称、字段的类型、是否反转如果是false,升序。true降序
|
||||||
|
BooleanQuery.Builder booleanQueryBuilder = new BooleanQuery.Builder();
|
||||||
|
//时间范围查询
|
||||||
|
Date startDate = logQuery.getStartTime();
|
||||||
|
Date endDate = logQuery.getEndTime();
|
||||||
|
|
||||||
|
if (startDate == null){
|
||||||
|
Calendar calendar=Calendar.getInstance();
|
||||||
|
calendar.set(1970, 0, 1);
|
||||||
|
startDate = calendar.getTime(); }
|
||||||
|
if (endDate == null){ endDate = new DateTime(); }
|
||||||
|
TermRangeQuery termRangeQuery = new TermRangeQuery(
|
||||||
|
"requestTime",
|
||||||
|
new BytesRef(DateUtil.format(startDate, "yyyy-MM-dd HH:mm:ss.SSS")),
|
||||||
|
new BytesRef(DateUtil.format(endDate, "yyyy-MM-dd HH:mm:ss.SSS")), true, true);
|
||||||
|
booleanQueryBuilder.add(termRangeQuery,BooleanClause.Occur.MUST);
|
||||||
|
|
||||||
|
// 字段之间的与或非关系,MUST表示and,MUST_NOT表示not,SHOULD表示or,有几个fields就必须有几个clauses
|
||||||
|
if (ObjectUtil.isNotEmpty(logQuery.getTraceId())){
|
||||||
|
TermQuery termQuery = new TermQuery(new Term("traceId", logQuery.getTraceId()));
|
||||||
|
booleanQueryBuilder.add(termQuery, BooleanClause.Occur.MUST);
|
||||||
|
}
|
||||||
|
if (ObjectUtil.isNotEmpty(logQuery.getLogLevel())){
|
||||||
|
TermQuery termQuery = new TermQuery(new Term("logLevel", logQuery.getLogLevel()));
|
||||||
|
booleanQueryBuilder.add(termQuery, BooleanClause.Occur.MUST);
|
||||||
|
}
|
||||||
|
if (ObjectUtil.isNotEmpty(logQuery.getSystem())) {
|
||||||
|
TermQuery termQuery = new TermQuery(new Term("system", logQuery.getSystem()));
|
||||||
|
booleanQueryBuilder.add(termQuery, BooleanClause.Occur.MUST);
|
||||||
|
}
|
||||||
|
if (ObjectUtil.isNotEmpty(logQuery.getRequestMethod())) {
|
||||||
|
TermQuery termQuery = new TermQuery(new Term("requestMethod", logQuery.getRequestMethod()));
|
||||||
|
booleanQueryBuilder.add(termQuery, BooleanClause.Occur.MUST);
|
||||||
|
}
|
||||||
|
if (Boolean.TRUE.equals(logQuery.getIsRequest())) {
|
||||||
|
Term traceid = new Term("traceId");
|
||||||
|
TermQuery termQuery = new TermQuery(traceid);
|
||||||
|
booleanQueryBuilder.add(termQuery, BooleanClause.Occur.MUST_NOT);
|
||||||
|
}
|
||||||
|
if (ObjectUtil.isNotEmpty(logQuery.getMessage())){
|
||||||
|
//查询解析器
|
||||||
|
QueryParser queryParser = new QueryParser("message", new IKAnalyzer(true));
|
||||||
|
Query query = queryParser.parse(logQuery.getMessage());
|
||||||
|
booleanQueryBuilder.add(query, BooleanClause.Occur.MUST);
|
||||||
|
}
|
||||||
|
|
||||||
|
TopFieldCollector collector = TopFieldCollector.create(new Sort(new SortField("time", SortField.Type.LONG,true)), 20000, 0);
|
||||||
|
searcher.search(booleanQueryBuilder.build(), collector);
|
||||||
|
TopDocs topDocs = collector.topDocs((logQuery.getPage()-1)*logQuery.getSize(), logQuery.getSize());
|
||||||
|
int totalSize = collector.getTotalHits();
|
||||||
|
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
|
||||||
|
|
||||||
|
List<LogRepositoryDTO> list = new ArrayList<>();
|
||||||
|
for (ScoreDoc scoreDoc : scoreDocs) {
|
||||||
|
Document doc = open.document(scoreDoc.doc);
|
||||||
|
LogRepositoryDTO dto = new LogRepositoryDTO();
|
||||||
|
dto.setSystem(doc.get("system"));
|
||||||
|
dto.setTraceId(doc.get("traceId"));
|
||||||
|
dto.setLogger(doc.get("logger"));
|
||||||
|
dto.setLogLevel(doc.get("logLevel"));
|
||||||
|
dto.setMessage(doc.get("message"));
|
||||||
|
dto.setRequestIp(doc.get("requestIp"));
|
||||||
|
dto.setRequestMethod(doc.get("requestMethod"));
|
||||||
|
dto.setRequestTime(doc.get("requestTime"));
|
||||||
|
dto.setThread(doc.get("thread"));
|
||||||
|
list.add(dto);
|
||||||
|
}
|
||||||
|
open.close();
|
||||||
|
directory.close();
|
||||||
|
page.addAll(list);
|
||||||
|
page.setTotal(scoreDocs.length);
|
||||||
|
res.put("total", totalSize);
|
||||||
|
}catch (Exception ex){
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
res.put("page",page);
|
||||||
|
return res;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Async
|
||||||
|
public void syncdemo() {
|
||||||
|
log.info("Async线程链路测试"+Thread.currentThread().getName());
|
||||||
|
log.error("Async线程链路测试"+Thread.currentThread().getName());
|
||||||
|
log.info("Async线程链路测试"+Thread.currentThread().getName());
|
||||||
|
log.info("线程链路测试"+Thread.currentThread().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
druid.filters.DruidFilter=org.nl.config.DruidFilter
|
||||||
@@ -42,16 +42,8 @@ spring:
|
|||||||
enabled: true
|
enabled: true
|
||||||
url-pattern: /druid/*
|
url-pattern: /druid/*
|
||||||
reset-enable: false
|
reset-enable: false
|
||||||
filter:
|
filters:
|
||||||
stat:
|
DruidFilter,stat
|
||||||
enabled: true
|
|
||||||
# 记录慢SQL
|
|
||||||
log-slow-sql: true
|
|
||||||
slow-sql-millis: 1000
|
|
||||||
merge-sql: true
|
|
||||||
wall:
|
|
||||||
config:
|
|
||||||
multi-statement-allow: true
|
|
||||||
redis:
|
redis:
|
||||||
#数据库索引
|
#数据库索引
|
||||||
database: ${REDIS_DB:2}
|
database: ${REDIS_DB:2}
|
||||||
@@ -162,3 +154,6 @@ sa-token:
|
|||||||
password:
|
password:
|
||||||
# 连接超时时间
|
# 连接超时时间
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
|
lucene:
|
||||||
|
index:
|
||||||
|
path: D:\lucene\index
|
||||||
|
|||||||
@@ -42,16 +42,8 @@ spring:
|
|||||||
enabled: true
|
enabled: true
|
||||||
url-pattern: /druid/*
|
url-pattern: /druid/*
|
||||||
reset-enable: false
|
reset-enable: false
|
||||||
filter:
|
filters:
|
||||||
stat:
|
DruidFilter,stat
|
||||||
enabled: true
|
|
||||||
# 记录慢SQL
|
|
||||||
log-slow-sql: true
|
|
||||||
slow-sql-millis: 1000
|
|
||||||
merge-sql: true
|
|
||||||
wall:
|
|
||||||
config:
|
|
||||||
multi-statement-allow: true
|
|
||||||
redis:
|
redis:
|
||||||
#数据库索引
|
#数据库索引
|
||||||
database: ${REDIS_DB:2}
|
database: ${REDIS_DB:2}
|
||||||
|
|||||||
@@ -41,16 +41,8 @@ spring:
|
|||||||
reset-enable: false
|
reset-enable: false
|
||||||
login-username: admin
|
login-username: admin
|
||||||
login-password: 123456
|
login-password: 123456
|
||||||
filter:
|
filters:
|
||||||
stat:
|
DruidFilter,stat
|
||||||
enabled: true
|
|
||||||
# 记录慢SQL
|
|
||||||
log-slow-sql: true
|
|
||||||
slow-sql-millis: 1000
|
|
||||||
merge-sql: true
|
|
||||||
wall:
|
|
||||||
config:
|
|
||||||
multi-statement-allow: true
|
|
||||||
redis:
|
redis:
|
||||||
#数据库索引
|
#数据库索引
|
||||||
database: ${REDIS_DB:15}
|
database: ${REDIS_DB:15}
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ security:
|
|||||||
mybatis-plus:
|
mybatis-plus:
|
||||||
configuration:
|
configuration:
|
||||||
map-underscore-to-camel-case: false
|
map-underscore-to-camel-case: false
|
||||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||||
mapper-locations:
|
mapper-locations:
|
||||||
- classpath:org.nl.**.mapper/*.xml
|
- classpath:org.nl.**.mapper/*.xml
|
||||||
global-config:
|
global-config:
|
||||||
|
|||||||
@@ -1,24 +1,12 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!--配置说明:
|
|
||||||
https://www.cnblogs.com/jybky/p/12204586.html
|
|
||||||
https://blog.csdn.net/wzygis/article/details/103189490
|
|
||||||
https://www.cnblogs.com/xrq730/p/8628945.html
|
|
||||||
https://www.jianshu.com/p/af5a7bab0e59
|
|
||||||
https://blog.csdn.net/wzygis/article/details/103189490
|
|
||||||
https://juejin.cn/post/6844903775631572999
|
|
||||||
-->
|
|
||||||
|
|
||||||
<configuration scan="true" scanPeriod="30 seconds" debug="false">
|
<configuration scan="true" scanPeriod="30 seconds" debug="false">
|
||||||
<contextName>nlAdmin</contextName>
|
<contextName>nlAdmin</contextName>
|
||||||
<property name="log.charset" value="utf-8"/>
|
<property name="log.charset" value="utf-8"/>
|
||||||
<property name="log.pattern"
|
<property name="log.pattern"
|
||||||
value="%black(%contextName-) %red(%d{yyyy-MM-dd HH:mm:ss.SSS}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}) - %gray(%msg%n)"/>
|
value="%black(%contextName-) %red(%d{yyyy-MM-dd HH:mm:ss.SSS}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}) - %gray(%msg%n)"/>
|
||||||
<springProperty scope="context" name="logPath" source="logging.file.path" defaultValue="logs"/>
|
|
||||||
<property name="LOG_HOME" value="${logPath}"/>
|
<property name="LOG_HOME" value="${logPath}"/>
|
||||||
<!--引入默认的一些设置-->
|
|
||||||
<!--<include resource="log/XrToMes.xml"/>
|
|
||||||
<include resource="log/MesToErp.xml"/>-->
|
|
||||||
<!-- <include resource="log/XgAgvDeviceDriver.xml"/>-->
|
|
||||||
|
|
||||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
<!-- 控制台高亮-->
|
<!-- 控制台高亮-->
|
||||||
@@ -27,18 +15,32 @@ https://juejin.cn/post/6844903775631572999
|
|||||||
<pattern>${log.pattern}</pattern>
|
<pattern>${log.pattern}</pattern>
|
||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
|
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
|
||||||
<property name="LOG_HOME" value="${logPath}"/>
|
|
||||||
<!-- 按照每天生成日志文件 -->
|
<!-- 按照每天生成日志文件 -->
|
||||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||||
<!--日志文件输出的文件名-->
|
<!--日志文件输出的文件名-->
|
||||||
<FileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}.%i.log</FileNamePattern>
|
<FileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}.%i.log</FileNamePattern>
|
||||||
<!--日志文件保留天数-->
|
<!--日志文件保留天数-->
|
||||||
<maxHistory>15</maxHistory>
|
<maxHistory>10</maxHistory>
|
||||||
<!--单个日志最大容量 至少10MB才能看得出来-->
|
<!--单个日志最大容量 至少10MB才能看得出来-->
|
||||||
<maxFileSize>50MB</maxFileSize>
|
<maxFileSize>100MB</maxFileSize>
|
||||||
|
<!--所有日志最多占多大容量-->
|
||||||
|
<totalSizeCap>20GB</totalSizeCap>
|
||||||
|
</rollingPolicy>
|
||||||
|
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||||
|
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
<appender name="ErpLogFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||||
|
<!--日志文件输出的文件名-->
|
||||||
|
<FileNamePattern>${LOG_HOME}/ErpLog/%d{yyyy-MM-dd}.%i.log</FileNamePattern>
|
||||||
|
<!--日志文件保留天数-->
|
||||||
|
<maxHistory>7</maxHistory>
|
||||||
|
<!--单个日志最大容量 至少10MB才能看得出来-->
|
||||||
|
<maxFileSize>100MB</maxFileSize>
|
||||||
<!--所有日志最多占多大容量-->
|
<!--所有日志最多占多大容量-->
|
||||||
<totalSizeCap>20GB</totalSizeCap>
|
<totalSizeCap>20GB</totalSizeCap>
|
||||||
</rollingPolicy>
|
</rollingPolicy>
|
||||||
@@ -46,122 +48,121 @@ https://juejin.cn/post/6844903775631572999
|
|||||||
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
|
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
|
||||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
|
||||||
</encoder>
|
</encoder>
|
||||||
|
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
<!--异步到文件-->
|
<!--异步到文件-->
|
||||||
<appender name="asyncFileAppender" class="com.yomahub.tlog.core.enhance.logback.async.AspectLogbackAsyncAppender">
|
<appender name="asyncFileAppender" class="com.yomahub.tlog.core.enhance.logback.async.AspectLogbackAsyncAppender">
|
||||||
<discardingThreshold>0</discardingThreshold>
|
<discardingThreshold>2</discardingThreshold>
|
||||||
<queueSize>500</queueSize>
|
<queueSize>500</queueSize>
|
||||||
<appender-ref ref="FILE"/>
|
<appender-ref ref="FILE"/>
|
||||||
</appender>
|
</appender>
|
||||||
|
<appender name="asyncERPFileAppender" class="ch.qos.logback.classic.AsyncAppender">
|
||||||
|
<discardingThreshold>2</discardingThreshold>
|
||||||
|
<queueSize>500</queueSize>
|
||||||
|
<appender-ref ref="ErpLogFile"/>
|
||||||
|
</appender>
|
||||||
|
<appender name="luceneAppender" class="org.nl.common.lucene.LuceneAppender" >
|
||||||
|
<properties>
|
||||||
|
<property>
|
||||||
|
<name>system</name>
|
||||||
|
<value>lms</value>
|
||||||
|
</property>
|
||||||
|
<property>
|
||||||
|
<name>logLevel</name>
|
||||||
|
<value>%level</value>
|
||||||
|
</property>
|
||||||
|
<property>
|
||||||
|
<name>requestMethod</name>
|
||||||
|
<value>%X{requestMethod}</value>
|
||||||
|
</property>
|
||||||
|
<property>
|
||||||
|
<name>requestTime</name>
|
||||||
|
<value>%d{yyyy-MM-dd HH:mm:ss.SSS}</value>
|
||||||
|
</property>
|
||||||
|
<property>
|
||||||
|
<name>requestIp</name>
|
||||||
|
<value>%X{requestIp}</value>
|
||||||
|
</property>
|
||||||
|
<property>
|
||||||
|
<name>thread</name>
|
||||||
|
<value>%thread</value>
|
||||||
|
</property>
|
||||||
|
<property>
|
||||||
|
<name>logger</name>
|
||||||
|
<value>%logger</value>
|
||||||
|
</property>
|
||||||
|
</properties>
|
||||||
|
</appender>
|
||||||
|
<appender name="asyncLuceneAppender" class="org.nl.common.lucene.AsyncLuceneAppender">
|
||||||
|
<appender-ref ref="luceneAppender" />
|
||||||
|
<queueSize>512</queueSize>
|
||||||
|
</appender>
|
||||||
|
|
||||||
<!--开发环境:打印控制台-->
|
<!--开发环境:打印控制台-->
|
||||||
<springProfile name="dev">
|
<springProfile name="dev">
|
||||||
<root level="debug">
|
<root level="info">
|
||||||
|
<appender-ref ref="asyncLuceneAppender"/>
|
||||||
<appender-ref ref="CONSOLE"/>
|
<appender-ref ref="CONSOLE"/>
|
||||||
</root>
|
</root>
|
||||||
<logger name="org.springframework" level="ERROR" additivity="false">
|
<logger name="jdbc" level="ERROR" additivity="true">
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
<appender-ref ref="asyncFileAppender"/>
|
||||||
</logger>
|
</logger>
|
||||||
<logger name="org.apache" level="ERROR" additivity="false">
|
<logger name="com.yomahub.tlog.web.interceptor.TLogWebInvokeTimeInterceptor" level="ERROR" additivity="true">
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
<appender-ref ref="asyncFileAppender"/>
|
||||||
</logger>
|
</logger>
|
||||||
<logger name="org.hibernate" level="ERROR" additivity="false">
|
<logger name="org.springframework" level="ERROR" additivity="true">
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
<appender-ref ref="asyncFileAppender"/>
|
||||||
</logger>
|
</logger>
|
||||||
<logger name="io.netty" level="ERROR" additivity="false">
|
<logger name="org.hibernate" level="ERROR" additivity="true">
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
<appender-ref ref="asyncFileAppender"/>
|
||||||
</logger>
|
</logger>
|
||||||
<logger name="jdbc" level="ERROR" additivity="false">
|
<logger name="org.quartz" level="ERROR" additivity="true">
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
<appender-ref ref="asyncFileAppender"/>
|
||||||
</logger>
|
</logger>
|
||||||
<logger name="io.lettuce" level="ERROR" additivity="false">
|
<logger name="com.google" level="ERROR" additivity="true">
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
<appender-ref ref="asyncFileAppender"/>
|
||||||
</logger>
|
</logger>
|
||||||
<logger name="com.fasterxml" level="ERROR" additivity="false">
|
<logger name="org.redisson" level="ERROR" additivity="true">
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
<appender-ref ref="asyncFileAppender"/>
|
||||||
</logger>
|
</logger>
|
||||||
<logger name="org.quartz" level="ERROR" additivity="false">
|
<logger name="org.nl.modules.wql" level="ERROR" additivity="true">
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
<appender-ref ref="asyncFileAppender"/>
|
||||||
</logger>
|
</logger>
|
||||||
<logger name="com.google" level="ERROR" additivity="false">
|
<logger name="org.springframework.data" level="ERROR" additivity="true">
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
|
||||||
</logger>
|
|
||||||
<logger name="springfox" level="ERROR" additivity="false">
|
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
|
||||||
</logger>
|
|
||||||
<logger name="log4jdbc" level="ERROR" additivity="false">
|
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
|
||||||
</logger>
|
|
||||||
<logger name="nl.basjes" level="ERROR" additivity="false">
|
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
<appender-ref ref="asyncFileAppender"/>
|
||||||
</logger>
|
</logger>
|
||||||
</springProfile>
|
</springProfile>
|
||||||
|
<springProfile name="prod">
|
||||||
|
<root level="info">
|
||||||
|
<appender-ref ref="asyncLuceneAppender"/>
|
||||||
|
<appender-ref ref="CONSOLE"/>
|
||||||
|
</root>
|
||||||
|
<logger name="jdbc" level="ERROR" additivity="true">
|
||||||
|
<appender-ref ref="asyncFileAppender"/>
|
||||||
|
</logger>
|
||||||
|
<logger name="org.springframework" level="ERROR" additivity="true">
|
||||||
|
<appender-ref ref="asyncFileAppender"/>
|
||||||
|
</logger>
|
||||||
|
<logger name="org.hibernate" level="ERROR" additivity="true">
|
||||||
|
<appender-ref ref="asyncFileAppender"/>
|
||||||
|
</logger>
|
||||||
|
<logger name="org.quartz" level="ERROR" additivity="true">
|
||||||
|
<appender-ref ref="asyncFileAppender"/>
|
||||||
|
</logger>
|
||||||
|
<logger name="com.google" level="ERROR" additivity="true">
|
||||||
|
<appender-ref ref="asyncFileAppender"/>
|
||||||
|
</logger>
|
||||||
|
<logger name="org.redisson" level="ERROR" additivity="true">
|
||||||
|
<appender-ref ref="asyncFileAppender"/>
|
||||||
|
</logger>
|
||||||
|
<logger name="org.nl.modules.wql" level="ERROR" additivity="true">
|
||||||
|
<appender-ref ref="asyncFileAppender"/>
|
||||||
|
</logger>
|
||||||
|
<logger name="org.springframework.data" level="ERROR" additivity="true">
|
||||||
|
<appender-ref ref="asyncFileAppender"/>
|
||||||
|
</logger>
|
||||||
|
</springProfile>
|
||||||
|
<!--测试环境:打印控制台-->
|
||||||
|
|
||||||
<!--生产环境:打印控制台和输出到文件-->
|
<!--生产环境:打印控制台和输出到文件-->
|
||||||
<springProfile name="prod">
|
|
||||||
<root level="debug">
|
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
|
||||||
</root>
|
|
||||||
<logger name="org.springframework" level="ERROR" additivity="false">
|
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
|
||||||
</logger>
|
|
||||||
<logger name="org.apache" level="ERROR" additivity="false">
|
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
|
||||||
</logger>
|
|
||||||
<logger name="org.hibernate" level="ERROR" additivity="false">
|
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
|
||||||
</logger>
|
|
||||||
<logger name="io.netty" level="ERROR" additivity="false">
|
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
|
||||||
</logger>
|
|
||||||
<logger name="jdbc" level="ERROR" additivity="false">
|
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
|
||||||
</logger>
|
|
||||||
<logger name="io.lettuce" level="ERROR" additivity="false">
|
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
|
||||||
</logger>
|
|
||||||
<logger name="com.fasterxml" level="ERROR" additivity="false">
|
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
|
||||||
</logger>
|
|
||||||
<logger name="org.quartz" level="ERROR" additivity="false">
|
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
|
||||||
</logger>
|
|
||||||
<logger name="com.google" level="ERROR" additivity="false">
|
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
|
||||||
</logger>
|
|
||||||
<logger name="springfox" level="ERROR" additivity="false">
|
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
|
||||||
</logger>
|
|
||||||
<logger name="log4jdbc" level="ERROR" additivity="false">
|
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
|
||||||
</logger>
|
|
||||||
<logger name="nl.basjes" level="ERROR" additivity="false">
|
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
|
||||||
</logger>
|
|
||||||
</springProfile>
|
|
||||||
|
|
||||||
|
|
||||||
<!--测试环境:打印控制台-->
|
|
||||||
<springProfile name="test">
|
|
||||||
<root level="info">
|
|
||||||
<appender-ref ref="asyncFileAppender"/>
|
|
||||||
</root>
|
|
||||||
<logger name="jdbc.audit" level="ERROR" additivity="false">
|
|
||||||
<appender-ref ref="CONSOLE"/>
|
|
||||||
</logger>
|
|
||||||
<logger name="jdbc.resultset" level="ERROR" additivity="false">
|
|
||||||
<appender-ref ref="CONSOLE"/>
|
|
||||||
</logger>
|
|
||||||
<logger name="springfox.documentation" level="ERROR" additivity="false">
|
|
||||||
<appender-ref ref="CONSOLE"/>
|
|
||||||
</logger>
|
|
||||||
<logger name="jdbc.resultsettable" level="ERROR" additivity="false">
|
|
||||||
<appender-ref ref="CONSOLE"/>
|
|
||||||
</logger>
|
|
||||||
<logger name="jdbc.sqlonly" level="ERROR" additivity="false">
|
|
||||||
<appender-ref ref="CONSOLE"/>
|
|
||||||
</logger>
|
|
||||||
</springProfile>
|
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|||||||
417
lms/nladmin-ui/src/views/monitor/eslog/view/index.vue
Normal file
417
lms/nladmin-ui/src/views/monitor/eslog/view/index.vue
Normal file
@@ -0,0 +1,417 @@
|
|||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<div class="head-container">
|
||||||
|
<!--工具栏-->
|
||||||
|
<el-form :inline="true" class="demo-form-inline" label-suffix=":" label-width="90px">
|
||||||
|
<el-form-item label="标签">
|
||||||
|
<el-select
|
||||||
|
v-model="system"
|
||||||
|
clearable
|
||||||
|
style="width: 100px; height: 35px;top: -5px;"
|
||||||
|
placeholder="所属标签"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in systemOptions"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="级别">
|
||||||
|
<el-select
|
||||||
|
v-model="logLevelValue"
|
||||||
|
clearable
|
||||||
|
style="width: 100px; height: 35px;top: -5px;"
|
||||||
|
placeholder="日志级别"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in labelsOptions"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="接口">
|
||||||
|
<el-input
|
||||||
|
v-model="requestMethod"
|
||||||
|
size="mini"
|
||||||
|
placeholder="请输入接口"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="关键字">
|
||||||
|
<el-input
|
||||||
|
v-model="message"
|
||||||
|
size="mini"
|
||||||
|
placeholder="请输入内容"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="链路追踪">
|
||||||
|
<el-input
|
||||||
|
v-model="traceId"
|
||||||
|
size="mini"
|
||||||
|
placeholder="请输入链路id"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="SQL日志" prop="filterSql">
|
||||||
|
<el-switch
|
||||||
|
v-model="filterSql"
|
||||||
|
active-color="#F56C6C"
|
||||||
|
inactive-color="#409EFF"
|
||||||
|
active-value="1"
|
||||||
|
inactive-valu="0"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="HTTP日志" prop="isRequest">
|
||||||
|
<el-switch
|
||||||
|
v-model="isRequest"
|
||||||
|
active-color="#409EFF"
|
||||||
|
inactive-color="#F56C6C"
|
||||||
|
active-value="1"
|
||||||
|
inactive-valu="0"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item v-show="!showOptions" label="时间范围">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="timeRange"
|
||||||
|
size="mini"
|
||||||
|
clearable
|
||||||
|
type="datetimerange"
|
||||||
|
range-separator="至"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
align="right"
|
||||||
|
@change="queryData"
|
||||||
|
@blur="queryData"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-show="showOptions" label="时间段">
|
||||||
|
<el-select v-model="timeZoneValue" filterable placeholder="请选择标签" size="mini" @change="queryData">
|
||||||
|
<el-option
|
||||||
|
v-for="item in timeZoneOptions"
|
||||||
|
:key="item.index"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-tooltip class="item" effect="dark" content="切换查询条件" placement="top">
|
||||||
|
<span class="el-icon-sort" @click="changeShow" />
|
||||||
|
</el-tooltip>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="显示条数">
|
||||||
|
<el-input-number
|
||||||
|
v-model="size"
|
||||||
|
size="mini"
|
||||||
|
controls-position="right"
|
||||||
|
:min="20"
|
||||||
|
:max="5000"
|
||||||
|
:step="10"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="当前页">
|
||||||
|
<el-input-number
|
||||||
|
v-model="page"
|
||||||
|
size="mini"
|
||||||
|
controls-position="right"
|
||||||
|
:min="1"
|
||||||
|
:max="2000"
|
||||||
|
:step="1"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="总条数">
|
||||||
|
<el-input
|
||||||
|
v-model="total"
|
||||||
|
size="small"
|
||||||
|
disabled
|
||||||
|
style="width: 110px"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-dropdown split-button type="primary" size="mini" @click="queryData">
|
||||||
|
查询
|
||||||
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
<el-dropdown-item v-for="(item, index) in runStatuOptions" :key="index" @click.native="startInterval(item)">{{ item.label }}</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button @click="clearLogs">清空日志</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
<!-- <div style="margin: 3px; min-height: 80vh;">
|
||||||
|
<el-table :data="logs">
|
||||||
|
<el-table-column label="ip" prop="requestIp" />
|
||||||
|
<el-table-column label="所属系统" prop="system" />
|
||||||
|
<el-table-column label="请求时间" prop="requestTime" />
|
||||||
|
<el-table-column label="traceId" prop="traceId" />
|
||||||
|
<el-table-column label="请求时间" prop="requestTime" />
|
||||||
|
<el-table-column label="请求接口" prop="requestMethod" />
|
||||||
|
<el-table-column label="logger" prop="logger" />
|
||||||
|
<el-table-column label="thread" prop="thread" />
|
||||||
|
<el-table-column label="message" prop="message" show-overflow-tooltip/>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
-->
|
||||||
|
<div style="margin: 3px; min-height: 80vh;">
|
||||||
|
<!--数据判空-->
|
||||||
|
<el-empty v-if="showEmpty" :description="emptyText" />
|
||||||
|
<!--数据加载-->
|
||||||
|
<el-card v-else shadow="hover" style="width: 100%;overflow-x: scroll" class="log-warpper">
|
||||||
|
<div style="width: 100%">
|
||||||
|
<div v-for="(log, index) in logs" :key="index">
|
||||||
|
<div>
|
||||||
|
<span style="color: #6c0a99;font-weight: 700">{{ log.system }}</span>
|
||||||
|
<span style="color: #13ce66">{{ log.thread }}</span>
|
||||||
|
<span :style="fontType(log.logLevel)">{{ log.logLevel }}</span>
|
||||||
|
<span>{{ log.requestIp }}</span>
|
||||||
|
<span style="color: #7c8db0">{{ log.requestTime }}</span>
|
||||||
|
<span style="color: chocolate">{{ log.traceId }}</span>
|
||||||
|
<span style="color: #7a6df0">{{ log.requestMethod }}</span>
|
||||||
|
<span style="margin: 5px;font-size: 15px" v-html="log.message">{{ log.message }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import logOperation from '@/views/monitor/eslog/view/loki'
|
||||||
|
|
||||||
|
let queryParam = {
|
||||||
|
logLevel: null,
|
||||||
|
system: null,
|
||||||
|
startTime: null,
|
||||||
|
endTime: null,
|
||||||
|
traceId: null,
|
||||||
|
requestMethod: null,
|
||||||
|
message: null,
|
||||||
|
filterSql: true,
|
||||||
|
isRequest: true,
|
||||||
|
page: null,
|
||||||
|
total: 0,
|
||||||
|
size: 20
|
||||||
|
}
|
||||||
|
export default {
|
||||||
|
name: 'ES',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
labelsOptions: [], // 所有标签和对应所有值数据
|
||||||
|
systemOptions: [], // 所有标签和对应所有值数据
|
||||||
|
logLevelValue: '',
|
||||||
|
system: '',
|
||||||
|
timeRange: [],
|
||||||
|
message: '',
|
||||||
|
requestMethod: '',
|
||||||
|
traceId: '',
|
||||||
|
size: 20,
|
||||||
|
logData: [],
|
||||||
|
filterSql: '1',
|
||||||
|
isRequest: '1',
|
||||||
|
logs: [], // 所有日志
|
||||||
|
showEmpty: true,
|
||||||
|
emptyText: '请选择标签',
|
||||||
|
page: 1,
|
||||||
|
runStatu: 'off',
|
||||||
|
runStatuOptions: [{
|
||||||
|
label: 'off',
|
||||||
|
value: 0
|
||||||
|
}, {
|
||||||
|
label: '5s',
|
||||||
|
value: 5000
|
||||||
|
}, {
|
||||||
|
label: '10s',
|
||||||
|
value: 10000
|
||||||
|
}, {
|
||||||
|
label: '1m',
|
||||||
|
value: 60000
|
||||||
|
}, {
|
||||||
|
label: '5m',
|
||||||
|
value: 300000
|
||||||
|
}, {
|
||||||
|
label: '30m',
|
||||||
|
value: 1800000
|
||||||
|
}],
|
||||||
|
timeZoneOptions: [{
|
||||||
|
label: '最近5分钟',
|
||||||
|
value: 300 * 1000
|
||||||
|
}, {
|
||||||
|
label: '最近15分钟',
|
||||||
|
value: 900 * 1000
|
||||||
|
}, {
|
||||||
|
label: '最近30分钟',
|
||||||
|
value: 1800 * 1000
|
||||||
|
}, {
|
||||||
|
label: '最近1小时',
|
||||||
|
value: 3600 * 1000
|
||||||
|
}, {
|
||||||
|
label: '最近3小时',
|
||||||
|
value: 3600 * 1000 * 3
|
||||||
|
}, {
|
||||||
|
label: '最近6小时',
|
||||||
|
value: 3600 * 1000 * 6
|
||||||
|
}, {
|
||||||
|
label: '最近12小时',
|
||||||
|
value: 3600 * 1000 * 12
|
||||||
|
}, {
|
||||||
|
label: '最近24小时',
|
||||||
|
value: 3600 * 1000 * 24
|
||||||
|
}, {
|
||||||
|
label: '最近2天',
|
||||||
|
value: 3600 * 1000 * 24 * 2
|
||||||
|
}, {
|
||||||
|
label: '最近7天',
|
||||||
|
value: 3600 * 1000 * 24 * 7
|
||||||
|
}, {
|
||||||
|
label: '最近15天',
|
||||||
|
value: 3600 * 1000 * 24 * 15
|
||||||
|
}],
|
||||||
|
timeZoneValue: '',
|
||||||
|
showOptions: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.initLabelsValues('logLevel')
|
||||||
|
this.initLabelsValues('system')
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
fontType(level) {
|
||||||
|
if (level === 'INFO') {
|
||||||
|
return { 'color': '#1b6cc4' }
|
||||||
|
}
|
||||||
|
if (level === 'ERROR') {
|
||||||
|
return { 'color': '#e30a0a' }
|
||||||
|
}
|
||||||
|
if (level === 'DEBUG') {
|
||||||
|
return { 'color': '#1e2022' }
|
||||||
|
}
|
||||||
|
return { 'color': '#a74dc6' }
|
||||||
|
},
|
||||||
|
initLabelsValues(type) {
|
||||||
|
logOperation.labelsValues(type).then(res => {
|
||||||
|
if (type === 'logLevel') {
|
||||||
|
this.labelsOptions = res
|
||||||
|
}
|
||||||
|
if (type === 'system') {
|
||||||
|
this.systemOptions = res
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
queryData() {
|
||||||
|
// 清空查询数据
|
||||||
|
this.clearParam()
|
||||||
|
queryParam.logLevel = this.logLevelValue
|
||||||
|
const time = new Date()
|
||||||
|
if (this.timeZoneValue !== '') {
|
||||||
|
queryParam.startTime = new Date(((time.getTime() - this.timeZoneValue)))
|
||||||
|
}
|
||||||
|
if (this.timeRange !== '' && this.timeRange.length > 0) {
|
||||||
|
queryParam.startTime = this.timeRange[0]
|
||||||
|
queryParam.endTime = this.timeRange[1]
|
||||||
|
}
|
||||||
|
queryParam.message = this.message.replace(/^\s*|\s*$/g, '')
|
||||||
|
queryParam.filterSql = this.filterSql === '1'
|
||||||
|
queryParam.isRequest = this.filterSql === '1'
|
||||||
|
queryParam.traceId = this.traceId
|
||||||
|
queryParam.requestMethod = this.requestMethod
|
||||||
|
queryParam.size = this.size
|
||||||
|
queryParam.page = this.page
|
||||||
|
queryParam.system = this.system
|
||||||
|
|
||||||
|
logOperation.getLogData(queryParam).then(res => {
|
||||||
|
this.showEmpty = false
|
||||||
|
this.total = res.total
|
||||||
|
// 清空
|
||||||
|
this.logs = []
|
||||||
|
for (const j in res.page) { // 用push的方式将所有日志数组添加进去
|
||||||
|
this.logs.push(res.page[j])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
clearLogs() {
|
||||||
|
var message = '您确定要清空'
|
||||||
|
if (this.system !== '' && this.system !== null) {
|
||||||
|
message += '标签为:' + this.system + ' '
|
||||||
|
}
|
||||||
|
message += '10天前的日志吗 ?'
|
||||||
|
this.$confirm(message, '确认信息', {
|
||||||
|
distinguishCancelAndClose: true,
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消'
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
// 清空查询数据
|
||||||
|
this.clearParam()
|
||||||
|
queryParam.logLevel = this.logLevelValue
|
||||||
|
const time = new Date()
|
||||||
|
if (this.timeZoneValue !== '') {
|
||||||
|
queryParam.startTime = new Date(((time.getTime() - this.timeZoneValue)))
|
||||||
|
}
|
||||||
|
if (this.timeRange !== '' && this.timeRange.length > 0) {
|
||||||
|
queryParam.startTime = this.timeRange[0]
|
||||||
|
queryParam.endTime = this.timeRange[1]
|
||||||
|
}
|
||||||
|
queryParam.message = this.message.replace(/^\s*|\s*$/g, '')
|
||||||
|
queryParam.traceId = this.traceId
|
||||||
|
queryParam.requestMethod = this.requestMethod
|
||||||
|
queryParam.system = this.system
|
||||||
|
|
||||||
|
logOperation.clearLogs(queryParam).then(res => {
|
||||||
|
this.queryData()
|
||||||
|
this.$message({
|
||||||
|
type: 'info',
|
||||||
|
message: '清除成功'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(action => {
|
||||||
|
this.$message({
|
||||||
|
type: 'info',
|
||||||
|
message: action === 'cancel'
|
||||||
|
? '已取消'
|
||||||
|
: '已取消'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
changetype() {
|
||||||
|
|
||||||
|
},
|
||||||
|
clearParam() {
|
||||||
|
queryParam = {
|
||||||
|
logLevel: null,
|
||||||
|
startTime: null,
|
||||||
|
endTime: null,
|
||||||
|
message: null,
|
||||||
|
traceId: null,
|
||||||
|
isRequest: true,
|
||||||
|
filterSql: true,
|
||||||
|
size: 20
|
||||||
|
}
|
||||||
|
},
|
||||||
|
changeShow() {
|
||||||
|
// 清空数据
|
||||||
|
this.timeZoneValue = ''
|
||||||
|
this.timeRange = []
|
||||||
|
this.showOptions = !this.showOptions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.log-warpper {
|
||||||
|
white-space: nowrap;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
26
lms/nladmin-ui/src/views/monitor/eslog/view/loki.js
Normal file
26
lms/nladmin-ui/src/views/monitor/eslog/view/loki.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getLogData(param) {
|
||||||
|
return request({
|
||||||
|
url: '/api/esLog/query',
|
||||||
|
method: 'post',
|
||||||
|
data: param
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function labelsValues(type) {
|
||||||
|
return request({
|
||||||
|
url: '/api/esLog/labels/' + type,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearLogs(param) {
|
||||||
|
return request({
|
||||||
|
url: '/api/esLog/clearLogs',
|
||||||
|
method: 'delete',
|
||||||
|
data: param
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default { getLogData, labelsValues, clearLogs }
|
||||||
@@ -31,18 +31,18 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="username" label="用户名" />
|
<el-table-column prop="username" label="用户名" />
|
||||||
<el-table-column prop="request_ip" label="IP" />
|
<el-table-column prop="requestIp" label="IP" />
|
||||||
<el-table-column show-overflow-tooltip prop="address" label="IP来源" />
|
<el-table-column :show-overflow-tooltip="true" prop="address" label="IP来源" />
|
||||||
<el-table-column prop="description" label="描述" show-overflow-tooltip />
|
<el-table-column prop="description" label="描述" />
|
||||||
<el-table-column prop="browser" label="浏览器" min-width="120" show-overflow-tooltip />
|
<el-table-column prop="browser" label="浏览器" />
|
||||||
<el-table-column prop="create_time" label="创建日期" min-width="100" show-overflow-tooltip>
|
<el-table-column prop="createTime" label="创建日期">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<span>{{ parseTime(scope.row.create_time) }}</span>
|
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="异常详情" width="100px">
|
<el-table-column label="异常详情" width="100px">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button size="mini" type="text" @click="info(scope.row.log_id)">查看详情</el-button>
|
<el-button size="mini" type="text" @click="info(scope.row.id)">查看详情</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -78,14 +78,14 @@ export default {
|
|||||||
add: false,
|
add: false,
|
||||||
edit: false,
|
edit: false,
|
||||||
del: false,
|
del: false,
|
||||||
download: false
|
download: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 获取异常详情
|
// 获取异常详情
|
||||||
info(log_id) {
|
info(id) {
|
||||||
this.dialog = true
|
this.dialog = true
|
||||||
getErrDetail(log_id).then(res => {
|
getErrDetail(id).then(res => {
|
||||||
this.errorInfo = res.exception
|
this.errorInfo = res.exception
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -31,10 +31,10 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="username" label="用户名" />
|
<el-table-column prop="username" label="用户名" />
|
||||||
<el-table-column prop="request_ip" label="IP" />
|
<el-table-column prop="requestIp" label="IP" />
|
||||||
<el-table-column show-overflow-tooltip prop="address" label="IP来源" />
|
<el-table-column :show-overflow-tooltip="true" prop="address" label="IP来源" />
|
||||||
<el-table-column prop="description" label="描述" show-overflow-tooltip />
|
<el-table-column prop="description" label="描述" />
|
||||||
<el-table-column prop="browser" label="浏览器" min-width="120" show-overflow-tooltip />
|
<el-table-column prop="browser" label="浏览器" />
|
||||||
<el-table-column prop="time" label="请求耗时" align="center">
|
<el-table-column prop="time" label="请求耗时" align="center">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-tag v-if="scope.row.time <= 300">{{ scope.row.time }}ms</el-tag>
|
<el-tag v-if="scope.row.time <= 300">{{ scope.row.time }}ms</el-tag>
|
||||||
@@ -42,9 +42,9 @@
|
|||||||
<el-tag v-else type="danger">{{ scope.row.time }}ms</el-tag>
|
<el-tag v-else type="danger">{{ scope.row.time }}ms</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="create_time" label="创建日期" width="180px">
|
<el-table-column prop="createTime" label="创建日期" width="180px">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<span>{{ parseTime(scope.row.create_time) }}</span>
|
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -72,7 +72,7 @@ export default {
|
|||||||
add: false,
|
add: false,
|
||||||
edit: false,
|
edit: false,
|
||||||
del: false,
|
del: false,
|
||||||
download: false
|
download: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<el-input
|
<el-input
|
||||||
v-model="query.blurry"
|
v-model="query.blurry"
|
||||||
clearable
|
clearable
|
||||||
size="mini"
|
size="small"
|
||||||
placeholder="请输入你要搜索的内容"
|
placeholder="请输入你要搜索的内容"
|
||||||
style="width: 200px;"
|
style="width: 200px;"
|
||||||
class="filter-item"
|
class="filter-item"
|
||||||
|
|||||||
Reference in New Issue
Block a user