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.pswp.cn/web/40115.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/40115.shtml
英文地址,請注明出處:http://en.pswp.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;它用于檢測設備是…

數據驅動測試實踐:Postman 中使用數據文件的指南

Postman 是一個強大的 API 開發和測試工具&#xff0c;它支持數據驅動測試&#xff0c;允許測試者使用外部數據文件來驅動測試&#xff0c;實現測試用例的參數化。數據驅動測試可以顯著提高測試效率&#xff0c;減少重復工作&#xff0c;并允許測試用例覆蓋更廣泛的輸入場景。本…

一文了解常見DNS問題

當企業的DNS出現故障時&#xff0c;為不影響企業的正常運行&#xff0c;團隊需要能夠快速確定問題的性質和范圍。那么有哪些常見的DNS問題呢&#xff1f; 域名解析失敗&#xff1a; 當您輸入一個域名&#xff0c;但無法獲取到與之對應的IP地址&#xff0c;導致無法訪問相應的網…

【代碼隨想錄算法訓練營第五十九天|卡碼網110.字符串接龍、105.有向圖的完全可達性、106.島嶼的周長】

文章目錄 卡碼網110.字符串接龍105.有向圖的完全可達性106.島嶼的周長 卡碼網110.字符串接龍 這題是在字符串上進行廣搜&#xff0c;字符串廣搜是對一個字符串按照位置來搜索&#xff0c;與原字符串只有一個位置字符不同那么就是在原字符串的基礎上距離加1。因此需要一個字典來…

獲取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…

SQLAlchemy批量操作數據

批量插入 session.bulk_insert_mappings(ModelClass, list(dict()))批量更新 session.bulk_update_mappings(ModelClass, list(dict())

Flutter的生命周期方法

Flutter的生命周期執行時機可以分為兩個主要部分&#xff1a;Flutter本身的組件生命周期&#xff08;widget生命周期&#xff09;和平臺相關的應用程序生命周期&#xff08;APP生命周期&#xff09;。 Widget生命周期 Widget生命周期可以細分為三個階段&#xff1a; 初始化階…

centos ssh一鍵升級到9.8版本腳本

背景 前端時間暴露出ssh漏洞&#xff0c;需要將服務器ssh版本&#xff0c;目前ssh版本最新版為9.8&#xff0c;故在服務器測試&#xff0c;準備將所有服務器ssh版本升級。腳本在centos7.6上親測可用。#!/bin/bash #Author Mr zhangECHO_GREEN() {echo -e "\033[32m $1...…

昇思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為目標顏色