Java实现日志全链路追踪.精确到一次请求的全部流程

广大程序员在排除线上问题时,会经常遇见各种BUG.处理这些BUG的时候日志就格外的重要.只有完善的日志才能快速有效的定位问题.为了提高BUG处理效率.我决定在日志上面优化.实现每次请求有统一的id.通过id能获取当前接口的全链路流程走向. 

实现效果如下: 一次查询即可找到所有关键信息.不再被多线程日志进行困扰了.

1:日志打印框架log4j ->  logback

logback是springboot默认自带的日志框架。不仅速度更快,而且内存占用也更小. (如果之前没用过log4j的建议先去学习下怎么使用).

打印日志的配置文件如下:  logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds">
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<jmxConfigurator/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<Target>System.out</Target>
<encoder>
<charset>UTF-8</charset>
<pattern>%d - [%t] %-5p %c:%L %X - %m%n</pattern>
</encoder>
</appender>
<appender name="DAILY_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<Append>true</Append>
<!--  日志输出路径 -->
<File>/opt/logs/logOut.log</File>
<encoder>
<charset>UTF-8</charset>
<pattern>%d - [%t] %-5p %c:%L %X - %m%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>/opt/logs/logOut.log.%d{yyyy-MM-dd}</fileNamePattern>
<maxHistory>7</maxHistory>
</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][%X{traceId}] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>/opt/logs/logOut-error.log</File>
<Append>true</Append>
<encoder>
<charset>UTF-8</charset>
<pattern>%d - [%t] %-5p %c:%L %X - %m%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>/opt/logs/logOut-error.log.%d{yyyy-MM-dd}</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
</appender><logger name="org.springframework" level="INFO"/>
<root level="INFO">
<appender-ref ref="DAILY_FILE"/>
<appender-ref ref="ROLLING_FILE"/>
</root>
</configuration>

重点是这行代码

<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread][%X{traceId}] %-5level %logger{50} - %msg%n</pattern>

此时的配置文件打印只能出现 年月日-线程名这些关键信息.无法获得每次请求的唯一id.所以我们需要创建一个拦截器.将每次请求生成一个id.通过id把本次请求覆盖到每个流程中.

2.1: 编写 http请求 拦截器

public class TraceWebInterceptor extends HandlerInterceptorAdapter {private static final Logger LOGGER = LoggerFactory.getLogger(TraceWebInterceptor.class);@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {request.setAttribute("startTime", System.currentTimeMillis());//traceOrigin、traceCaller、traceIdString traceOrigin = request.getHeader(TraceConstants.LOG_TRACE_ORIGIN);String traceCaller = request.getHeader(TraceConstants.LOG_TRACE_CALLER);String traceId = request.getHeader(TraceConstants.LOG_TRACE_ID);//如果不存在traceId需要生成if (StringUtils.isBlank(traceId)) {boolean generate = TraceUtil.loadTraceInfo();if(generate) {LOGGER.debug("[生成追踪信息]" + TraceUtil.getTraceInfoString());}}else {//设置MDCMDC.put(TraceConstants.LOG_TRACE_ORIGIN, traceOrigin);MDC.put(TraceConstants.LOG_TRACE_CALLER, traceCaller);MDC.put(TraceConstants.LOG_TRACE_ID, traceId);}//IPString traceIp = IpUtil.getIp(request);MDC.put(TraceConstants.LOG_TRACE_IP, traceIp);//响应返回response.setHeader(TraceConstants.LOG_TRACE_ID, TraceUtil.getTraceId());return super.preHandle(request, response, handler);}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws IOException {if (LOGGER.isInfoEnabled()) {long upmsStartTime = (long) request.getAttribute("startTime");long upmsEndTime = System.currentTimeMillis();long upmsIntervalTime = upmsEndTime - upmsStartTime;LOGGER.info("{} {}接口耗时{}毫秒", request.getRequestURL(), request.getMethod(), upmsIntervalTime);}MDC.clear();}

2.2 编写Config类, 将拦截器TraceWebInterceptor添加到容器

@Configuration
@ConditionalOnClass({HandlerInterceptorAdapter.class, MDC.class, HttpServletRequest.class})
public class TraceWebAutoConfiguration implements WebMvcConfigurer {private static List<String> EXCLUDE_PATHS = new ArrayList<>();@Value("${" + TraceConstants.CONFIG_TRACE_EXCLUDE_PATHS + ":}")private String excludePaths;@Beanpublic TraceWebInterceptor traceWebInterceptor() {return new TraceWebInterceptor();}@Overridepublic void addInterceptors(InterceptorRegistry registry) {EXCLUDE_PATHS.add("/error");EXCLUDE_PATHS.add("/actuator/**");if (StringUtils.isNotBlank(excludePaths)) {if (excludePaths.contains(",")) {String[] split = excludePaths.split(",");EXCLUDE_PATHS.addAll(Arrays.asList(split));} else {EXCLUDE_PATHS.add(excludePaths);}}//该方式不能过全部过滤掉registry.addInterceptor(traceWebInterceptor()).order(-100).excludePathPatterns(EXCLUDE_PATHS);}
}

2.3 编写工具类

import javax.servlet.http.HttpServletRequest;public class IpUtil {private static final String UNKNOWN = "unknown";public static String getIp(HttpServletRequest request) {if (request == null) {return UNKNOWN;}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("X-Forwarded-For");}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.getHeader("X-Real-IP");}if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;}
}

public class TraceConstants {public static final String LOG_TRACE_ORIGIN = "traceOrigin";public static final String LOG_TRACE_CALLER = "traceCaller";public static final String LOG_TRACE_IP = "traceIp";public static final String LOG_TRACE_ID = "traceId";public static final String CONFIG_TRACE_EXCLUDE_PATHS = "trace.exclude.paths";public TraceConstants() {}
}

import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;import java.util.UUID;public class TraceUtil {private static boolean simbaHttpClientInterceptorFlag = true;private static boolean sdkInterceptorFlag = false;private static String applicationName;public TraceUtil() {}public static void setApplicationName(String applicationName) {TraceUtil.applicationName = applicationName;}public static String getApplicationName() {return applicationName;}public static boolean getSimbaHttpClientInterceptorFlag() {return simbaHttpClientInterceptorFlag;}public static void setSimbaHttpClientInterceptorFlag(boolean simbaHttpClientInterceptorFlag) {TraceUtil.simbaHttpClientInterceptorFlag = simbaHttpClientInterceptorFlag;}public static boolean getSdkInterceptorFlag() {return sdkInterceptorFlag;}public static void setSdkInterceptorFlag(boolean sdkInterceptorFlag) {TraceUtil.sdkInterceptorFlag = sdkInterceptorFlag;}public static void setTraceCaller(String traceCaller) {MDC.put("traceCaller", traceCaller);}public static String getTraceCaller() {return MDC.get("traceCaller");}public static void setTraceOrigin(String traceOrigin) {MDC.put("traceOrigin", traceOrigin);}public static String getTraceOrigin() {return MDC.get("traceOrigin");}public static void setTraceId(String traceId) {MDC.put("traceId", traceId);}public static void removeTraceId() {MDC.remove("traceId");}public static void clearMdc() {MDC.clear();}public static String getTraceId() {return MDC.get("traceId");}public static String genTraceId() {return UUID.randomUUID().toString().replace("-", "");}public static String getTraceIp() {return MDC.get("traceIp");}public static void setTraceIp(String traceIp) {MDC.put("traceIp", traceIp);}public static boolean loadTraceInfo() {boolean generate = false;String traceId = getTraceId();if (StringUtils.isBlank(traceId)) {traceId = genTraceId();generate = true;}setTraceId(traceId);return generate;}public static String getTraceInfoString() {return "TraceId:" + getTraceId() + ". traceCaller:" + getTraceCaller() + ". traceOrigin:" + getTraceOrigin();}
}

import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;@Configuration
@ConditionalOnClass({HandlerInterceptorAdapter.class, MDC.class, HttpServletRequest.class})
public class TraceWebAutoConfiguration implements WebMvcConfigurer {private static List<String> EXCLUDE_PATHS = new ArrayList<>();@Value("${" + TraceConstants.CONFIG_TRACE_EXCLUDE_PATHS + ":}")private String excludePaths;@Beanpublic TraceWebInterceptor traceWebInterceptor() {return new TraceWebInterceptor();}@Overridepublic void addInterceptors(InterceptorRegistry registry) {EXCLUDE_PATHS.add("/error");EXCLUDE_PATHS.add("/actuator/**");if (StringUtils.isNotBlank(excludePaths)) {if (excludePaths.contains(",")) {String[] split = excludePaths.split(",");EXCLUDE_PATHS.addAll(Arrays.asList(split));} else {EXCLUDE_PATHS.add(excludePaths);}}//该方式不能过全部过滤掉registry.addInterceptor(traceWebInterceptor()).order(-100).excludePathPatterns(EXCLUDE_PATHS);}
}

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;public class TraceWebInterceptor extends HandlerInterceptorAdapter {private static final Logger LOGGER = LoggerFactory.getLogger(TraceWebInterceptor.class);@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {request.setAttribute("startTime", System.currentTimeMillis());//traceOrigin、traceCaller、traceIdString traceOrigin = request.getHeader(TraceConstants.LOG_TRACE_ORIGIN);String traceCaller = request.getHeader(TraceConstants.LOG_TRACE_CALLER);String traceId = request.getHeader(TraceConstants.LOG_TRACE_ID);//如果不存在traceId需要生成if (StringUtils.isBlank(traceId)) {boolean generate = TraceUtil.loadTraceInfo();if (generate) {LOGGER.debug("[生成追踪信息]" + TraceUtil.getTraceInfoString());}} else {//设置MDCMDC.put(TraceConstants.LOG_TRACE_ORIGIN, traceOrigin);MDC.put(TraceConstants.LOG_TRACE_CALLER, traceCaller);MDC.put(TraceConstants.LOG_TRACE_ID, traceId);}//IPString traceIp = IpUtil.getIp(request);MDC.put(TraceConstants.LOG_TRACE_IP, traceIp);//响应返回response.setHeader(TraceConstants.LOG_TRACE_ID, TraceUtil.getTraceId());return super.preHandle(request, response, handler);}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws IOException {if (LOGGER.isInfoEnabled()) {long upmsStartTime = (long) request.getAttribute("startTime");long upmsEndTime = System.currentTimeMillis();long upmsIntervalTime = upmsEndTime - upmsStartTime;LOGGER.info("{} {}接口耗时{}毫秒", request.getRequestURL(), request.getMethod(), upmsIntervalTime);}MDC.clear();}
}

import org.slf4j.MDC;import java.util.Map;
import java.util.concurrent.*;public class WrapUtil {public static <T> Callable<T> wrap(final Callable<T> callable, final Map<String, String> context) {return () -> {if (context == null) {MDC.clear();} else {MDC.setContextMap(context);}TraceUtil.loadTraceInfo();try {return callable.call();} finally {MDC.clear();}};}public static <T> Callable<T> wrap(final Callable<T> callable) {return wrap(callable, MDC.getCopyOfContextMap());}public static Runnable wrap(final Runnable runnable, final Map<String, String> context) {return () -> {if (context == null) {MDC.clear();} else {MDC.setContextMap(context);}TraceUtil.loadTraceInfo();try {runnable.run();} finally {MDC.clear();}};}public static Runnable wrap(final Runnable runnable) {return wrap(runnable, MDC.getCopyOfContextMap());}public static ThreadPoolExecutor newThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,RejectedExecutionHandler handler) {return new ThreadPoolExecutorMdcWrapper(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);}public static ThreadPoolExecutor newThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {return new ThreadPoolExecutorMdcWrapper(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);}public static ThreadPoolExecutor newThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,BlockingQueue<Runnable> workQueue) {return new ThreadPoolExecutorMdcWrapper(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);}public static ThreadPoolExecutor newThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler) {return new ThreadPoolExecutorMdcWrapper(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);}public static ForkJoinPool newForkJoinPool() {return new ForkJoinPoolMdcWrapper();}public static class ThreadPoolExecutorMdcWrapper extends ThreadPoolExecutor {public ThreadPoolExecutorMdcWrapper(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,BlockingQueue<Runnable> workQueue) {super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);}public ThreadPoolExecutorMdcWrapper(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);}public ThreadPoolExecutorMdcWrapper(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);}public ThreadPoolExecutorMdcWrapper(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,RejectedExecutionHandler handler) {super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);}@Overridepublic void execute(Runnable task) {super.execute(WrapUtil.wrap(task, MDC.getCopyOfContextMap()));}@Overridepublic <T> Future<T> submit(Runnable task, T result) {return super.submit(WrapUtil.wrap(task, MDC.getCopyOfContextMap()), result);}@Overridepublic <T> Future<T> submit(Callable<T> task) {return super.submit(WrapUtil.wrap(task, MDC.getCopyOfContextMap()));}@Overridepublic Future<?> submit(Runnable task) {return super.submit(WrapUtil.wrap(task, MDC.getCopyOfContextMap()));}}public static class ForkJoinPoolMdcWrapper extends ForkJoinPool {public ForkJoinPoolMdcWrapper() {super();}public ForkJoinPoolMdcWrapper(int parallelism) {super(parallelism);}public ForkJoinPoolMdcWrapper(int parallelism, ForkJoinWorkerThreadFactory factory,Thread.UncaughtExceptionHandler handler, boolean asyncMode) {super(parallelism, factory, handler, asyncMode);}@Overridepublic void execute(Runnable task) {super.execute(WrapUtil.wrap(task, MDC.getCopyOfContextMap()));}@Overridepublic <T> ForkJoinTask<T> submit(Runnable task, T result) {return super.submit(WrapUtil.wrap(task, MDC.getCopyOfContextMap()), result);}@Overridepublic <T> ForkJoinTask<T> submit(Callable<T> task) {return super.submit(WrapUtil.wrap(task, MDC.getCopyOfContextMap()));}}
}

把工具类加上后.此时运行项目. 如果报错就处理下依赖导包. 不报错就说明可以正常使用了. 然后发布代码.运行方法.去查看日志吧. 此时每次请求都已经生成唯一ID了.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/40115.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自定义一个背景图片的高度,随着容器高度的变化而变化,小于图片的高度时裁剪,大于时拉伸100%展示

1、通过js创建<image?>标签来获取背景图片的宽高比&#xff1b; 2、当元素的高度大于原有比例计算出来的高度时&#xff0c;背景图片的高度拉伸自适应100%&#xff0c;否则高度为auto&#xff0c;会自动被裁减 3、背景图片容器高度变化时&#xff0c;自动计算背景图片的…

Android network - NUD检测机制(Android 14)

Android network - NUD检测机制 1. 前言2. 源码分析2.1 ClientModeImpl2.2 IpClient2.3 IpReachabilityMonitor 1. 前言 在Android系统中&#xff0c;NUD&#xff08;Neighbor Unreachable Detection&#xff09;指的是网络中的邻居不可达检测机制&#xff0c;它用于检测设备是…

一文了解常见DNS问题

当企业的DNS出现故障时&#xff0c;为不影响企业的正常运行&#xff0c;团队需要能够快速确定问题的性质和范围。那么有哪些常见的DNS问题呢&#xff1f; 域名解析失败&#xff1a; 当您输入一个域名&#xff0c;但无法获取到与之对应的IP地址&#xff0c;导致无法访问相应的网…

获取VC账号,是成为亚马逊供应商的全面准备与必要条件

成为亚马逊的供应商&#xff0c;拥有VC&#xff08;Vendor Central&#xff09;账号&#xff0c;是众多制造商和品牌所有者的共同目标。这不仅代表了亚马逊对供应商的高度认可&#xff0c;也意味着获得了更多的销售机会和更广阔的市场前景。 全面准备与必要条件是获取VC账号的关…

代码转换成AST语法树移除无用代码console.log、import

公司中代码存在大量,因此产生 可以使用 @babel/parser 解析代码生成 AST (抽象语法树),然后使用 @babel/traverse 进行遍历并删除所有的 console.log 语句,最后使用 @babel/generator 生成修改后的代码。 这里有一个网址,可以线上解析代码转换成AST语法树: https://astex…

Python爬虫康复训练——笔趣阁《神魂至尊》

还是话不多说&#xff0c;很久没写爬虫了&#xff0c;来个bs4康复训练爬虫&#xff0c;正好我最近在看《神魂至尊》&#xff0c;爬个txt文件下来看看 直接上代码 """ 神魂至尊网址-https://www.bqgui.cc/book/1519/ """ import requests from b…

【C++】 解决 C++ 语言报错:未定义行为(Undefined Behavior)

文章目录 引言 未定义行为&#xff08;Undefined Behavior, UB&#xff09;是 C 编程中非常危险且难以调试的错误之一。未定义行为发生时&#xff0c;程序可能表现出不可预测的行为&#xff0c;导致程序崩溃、安全漏洞甚至硬件损坏。本文将深入探讨未定义行为的成因、检测方法…

零基础STM32单片机编程入门(七)定时器PWM波输出实战含源码视频

文章目录 一.概要二.PWM产生框架图三.CubeMX配置一个TIME输出1KHZ&#xff0c;占空比50%PWM波例程1.硬件准备2.创建工程3.测量波形结果 四.CubeMX工程源代码下载五.讲解视频链接地址六.小结 一.概要 脉冲宽度调制(PWM)&#xff0c;是英文“Pulse Width Modulation”的缩写&…

通过营销本地化解锁全球市场

在一个日益互联的世界里&#xff0c;企业必须接触到全球各地的不同受众。营销本地化是打开这些全球市场的关键。它包括调整营销材料&#xff0c;使其与不同地区的文化和语言细微差别产生共鸣。以下是有效的营销本地化如何推动您的全球扩张&#xff0c;并用实际例子来说明每一点…

UrbanGPT: Spatio-Temporal Large Language Models

1.文章信息 本次介绍的文章是2024年arxiv上一篇名为《UrbanGPT: Spatio-Temporal Large Language Models》的文章&#xff0c;UrbanGPT旨在解决城市环境中的时空预测问题&#xff0c;通过大语言模型&#xff08;LLM&#xff09;的强大泛化能力来应对数据稀缺的挑战。 2.摘要 Ur…

昇思MindSpore学习总结九——FCN语义分割

1、语义分割 图像语义分割&#xff08;semantic segmentation&#xff09;是图像处理和机器视觉技术中关于图像理解的重要一环&#xff0c;AI领域中一个重要分支&#xff0c;常被应用于人脸识别、物体检测、医学影像、卫星图像分析、自动驾驶感知等领域。 语义分割的目的是对图…

【楚怡杯】职业院校技能大赛 “Python程序开发”赛项样题三

Python程序开发实训 &#xff08;时量&#xff1a;240分钟&#xff09; 中国XX 实训说明 注意事项 1. 请根据提供的实训环境&#xff0c;检查所列的硬件设备、软件清单、材料清单是否齐全&#xff0c;计算机设备是否能正常使用。 2. 实训结束前&#xff0c;在实训平台提供的…

从数据到智能,英智私有大模型助力企业实现数智化发展

在数字化时代&#xff0c;数据已经成为企业最重要的资源。如何将这些数据转化为实际的业务价值&#xff0c;是每个企业面临的重要课题。英智利用业界领先的清洗、训练和微调技术&#xff0c;对企业数据进行深度挖掘和分析&#xff0c;定制符合企业业务场景的私有大模型&#xf…

筛选有合并单元格的数据

我们经常会使用合并单元格&#xff0c;比如下面表格&#xff0c;因为一个部门中会有不同的员工&#xff0c;就会出现如下表格&#xff1a; 但是当按部门去筛选的时候&#xff0c;会发现并不是我们预期的结果&#xff0c;部门列有空值&#xff0c;每个部门只有第一行数据可以被…

虚幻引擎 快速的色度抠图 Chroma Key 算法

快就完了 ColorTolerance_PxRange为容差&#xff0c;这里是0-255的输入&#xff0c;也就是px单位&#xff0c;直接用0-1可以更快 Key为目标颜色

PySide6 实现资源的加载:深入解析与实战案例

目录 1. 引言 2. 加载内置资源 3. 使用自定义资源文件&#xff08;.qrc&#xff09; 创建.qrc文件 编译.qrc文件 加载资源 4. 动态加载UI文件 使用Qt Designer设计UI 加载UI文件 5. 注意事项与最佳实践 6. 结论 在开发基于PySide6的桌面应用程序时&…

什么是 DDoS 攻击及如何防护DDOS攻击

自进入互联网时代&#xff0c;网络安全问题就一直困扰着用户&#xff0c;尤其是DDOS攻击&#xff0c;一直威胁着用户的业务安全。而高防IP被广泛用于增强网络防护能力。今天我们就来了解下关于DDOS攻击&#xff0c;以及可以防护DDOS攻击的高防IP该如何正确选择使用。 一、什么是…

个人引导页+音乐炫酷播放器(附加源码)

个人引导页音乐炫酷播放器 效果图部分源码完整源码领取下期更新内容 效果图 部分源码 //网站动态标题开始 var OriginTitile document.title, titleTime; document.addEventListener("visibilitychange", function() {if (document.hidden) {document.title "…

Python学习从0开始——Kaggle实践可视化001

Python学习从0开始——Kaggle实践可视化001 一、创建和加载数据集二、数据预处理1.按name检查&#xff0c;处理重复值&#xff08;查重&#xff09;2.查看存在缺失值的列并处理&#xff08;缺失值处理&#xff09;2.1按行或列查看2.2无法推测的数据2.3可由其它列推测的数据 3.拆…

QT实现GIF动图显示(小白版,可直接copy使用)

需要你自己提前设置好动图的位置&#xff0c;本例中存放于"/Users/PLA/PLA/PLA.gif widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QMovie> #include <QLabel>class Widget : public QWidget {Q_OBJECTpublic:explicit Wid…