当前位置: 首页 > news >正文

Logback日志异步打印接入指南,输出自定义业务数据

背景

随着应用的请求量上升,日志输出量也会成线性比例的上升,给磁盘IO带来压力与性能瓶颈。应用也遇到了线程池满,是因为大量线程卡在输出日志。为了缓解日志同步打印,会采取异步打印日志。这样会引起日志中的追踪id丢失,不能基于追踪id查询相关日志,给问题解决带来新的挑战。

目标

  • 业务数据传递
    • 在日志输出中,业务可以传递用户自定义数据并输出到日志中,并自动构建字段索引,便于快速查询。(包含同步输出)
  • 轻量级接入

技术方案

基于SLF4J日志事件LoggingEvent和映射诊断上下文MDC

  • 在Logback日志事件LoggingEvent implements ILoggingEvent进入日志异步追加器AsyncAppender extends AsyncAppenderBase<ILoggingEvent>的队列blockingQueue之前,把数据状态临时存储到MDC适配器LogbackMDCAdaptermdcPropertyMap线程本地变量副本中。
  • 在组装日志数据前从其取出这些临时的内存数据状态,并组装到最终的日志文本数据中。

具体实现

XxxJsonLayout

package com.xxx.logback;import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.contrib.json.classic.JsonLayout;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Map;import org.apache.skywalking.apm.toolkit.trace.TraceContext;/*** JSON格式布局输出*/
public class XxxJsonLayout extends JsonLayout {/*** 零时区 UTC 0* 协调世界时(UTC)*/private static final ZoneId ZONE_ID_0 = ZoneId.ofOffset("UTC", ZoneOffset.UTC);/*** 东八区 UTC+8*/private static final ZoneId ZONE_ID_8 = ZoneId.of("Asia/Shanghai");private static final String AT_TIMESTAMP_ATTR_NAME = "@timestamp";@Overrideprotected void addCustomDataToJsonMap(Map<String, Object> map, ILoggingEvent event) {String timestampFormat = Instant.ofEpochMilli(event.getTimeStamp()).atZone(ZONE_ID_8).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);map.put(TIMESTAMP_ATTR_NAME, timestampFormat);String atTimestampFormat = Instant.ofEpochMilli(event.getTimeStamp()).atZone(ZONE_ID_0).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);// ES record create timestampmap.put(AT_TIMESTAMP_ATTR_NAME, atTimestampFormat);// log async appender print, app data pass by MDC// 日志异步打印,应用日志数据从MDC传递if (this.isIncludeMDC()) {Map<String, String> mdcPropertyMap = event.getMDCPropertyMap();map.putAll(MdcUtil.applyAsMap(mdcPropertyMap));}String traceId = TraceContext.traceId();// 日志异步打印时,追踪id为空,需要从MDC传递if (!isEmptyTraceId(traceId)) {map.put(MdcUtil.TRACE_ID_KEY, traceId);}}/*** 空的追踪身份*/private static final String EMPTY_TRACE_CONTEXT_ID = "N/A";/*** 忽略的追踪*/private static final String IGNORE_TRACE = "Ignored_Trace";private static boolean isEmptyTraceId(String traceId) {return traceId == null || traceId.isEmpty()|| EMPTY_TRACE_CONTEXT_ID.equals(traceId);}
}

MdcUtil

package com.xxx.logback;import java.util.HashMap;
import java.util.Map;
import java.util.Set;import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.apache.skywalking.apm.toolkit.trace.TraceContext;
import org.slf4j.MDC;/*** Proxy of {@link MDC}.** @since 2024/4/13*/
@Slf4j
public final class MdcUtil {/*** 追踪身份*/static final String TRACE_ID_KEY = "traceId";public static void setTraceId() {MDC.put(TRACE_ID_KEY, TraceContext.traceId());}public static void setTraceId(String traceId) {MDC.put(TRACE_ID_KEY, traceId);}// 业务过程数据private static final String USER_ID = "userId";private static final String COACH_ID = "coachId";private static final String ADMIN_ID = "adminId";private static final String RESPONSE_TIME = "rt";private static final String RESPONSE_CODE = "code";private static final String API = "api";private static final String REMOTE_APP = "remoteApp";public static void setUserId(Long userId) {MDC.put(USER_ID, "" + userId);}public static void setCoachId(Long coachId) {MDC.put(COACH_ID, "" + coachId);}public static void setAdminId(Long adminId) {MDC.put(ADMIN_ID, "" + adminId);}public static void setResponseTime(long responseTime) {MDC.put(RESPONSE_TIME, Long.toString(responseTime));}public static void setResponseTime(int responseTime) {MDC.put(RESPONSE_TIME, Integer.toString(responseTime));}public static void setResponseCode(int responseCode) {MDC.put(RESPONSE_CODE, Integer.toString(responseCode));}public static void setResponseCode(String responseCode) {MDC.put(RESPONSE_CODE, responseCode);}public static void setApi(String api) {MDC.put(API, api);}public static void setRemoteApp(String remoteApp) {MDC.put(REMOTE_APP, remoteApp);}public static void clear() {MDC.clear();}/*** ES long data type*/private static final Set<String> LONG_DATA_KEY_SET = Sets.newHashSet(USER_ID, COACH_ID, ADMIN_ID, RESPONSE_TIME);public static Map<String, Object> applyAsMap(Map<String, String> mdcPropertyMap) {Map<String, Object> result = new HashMap<>(mdcPropertyMap.size());mdcPropertyMap.forEach((key, value) -> {if (LONG_DATA_KEY_SET.contains(key)) {result.put(key, toLong(value, Long.MIN_VALUE));} else {result.put(key, value);}});return result;}private static long toLong(String str, long defaultValue) {if (str == null) {return defaultValue;} else {try {return Long.parseLong(str, 10);} catch (NumberFormatException e) {log.warn("parse string to long error, str={}", str);return defaultValue;}}}
}

XxxJsonLayoutEncoder

package com.xxx.logback;import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.contrib.jackson.JacksonJsonFormatter;
import ch.qos.logback.core.encoder.LayoutWrappingEncoder;import java.nio.charset.StandardCharsets;public class XxxJsonLayoutEncoder extends LayoutWrappingEncoder<ILoggingEvent> {@Overridepublic void start() {XxxJsonLayout jsonLayout = new XxxJsonLayout();jsonLayout.setContext(context);jsonLayout.setIncludeContextName(false);jsonLayout.setAppendLineSeparator(true);jsonLayout.setJsonFormatter(new JacksonJsonFormatter());jsonLayout.start();super.setCharset(StandardCharsets.UTF_8);super.setLayout(jsonLayout);super.start();}
}

应用如何接入

xxx-spring-boot-starter升级依赖版本

xxx-spring-boot-starter版本是2.7.18

<properties><xxx-spring-boot.version>2.7.18</xxx-spring-boot.version>
</properties><dependencyManagement><dependencies><dependency><groupId>com.spring.boot</groupId><artifactId>xxx-spring-boot-starter</artifactId><version>${xxx-spring-boot.version}</version></dependency></dependencies>
</dependencyManagement>

Logback日志配置

logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration><springProperty scope="context" name="appName" source="spring.application.name"/><include resource="org/springframework/boot/logging/logback/defaults.xml"/><property name="STDOUT_PATTERN" value="%d [%t] %5p %c - %m%n"/><property name="log.name" value="${appName}"/><property name="log.path" value="/home/admin/logs"/><springProperty scope="context" name="appName" source="spring.application.name"/><appender class="ch.qos.logback.core.rolling.RollingFileAppender" name="BIZ_LOG"><encoder class="com.xxx.logback.XxxJsonLayoutEncoder"/><file>${log.path}/${log.name}.log</file><rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"><fileNamePattern>${log.path}/${log.name}_%i.log</fileNamePattern><maxIndex>1</maxIndex></rollingPolicy><triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"><maxFileSize>100MB</maxFileSize></triggeringPolicy></appender><!-- report日志异步打印appender --><appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender"><!-- 不丢失日志(默认discardingThreshold=queueSize/5,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 --><discardingThreshold>0</discardingThreshold><!-- 默认队列深度,该值会影响性能.默认值256 --><queueSize>256</queueSize><!-- 当队列满了之后,后面阻塞的线程想要打印的日志就直接被丢弃,从而线程不会阻塞,但有可能会丢失日志--><neverBlock>true</neverBlock><appender-ref ref="BIZ_LOG"/></appender><logger name="report" level="info" additivity="false"><appender-ref ref="ASYNC"/></logger><root level="INFO"><appender-ref ref="ASYNC"/></root></configuration>

传递业务自定义数据到日志

使用MdcUtil传递用户id、教练id、优惠券id、商品id、交易订单id、支付订单id、物流订单id、api、responseTime、responseCode、追踪id等,从用户、教练、营销、商品、交易、物流等维度观测用户的实操路径。

以Dubbo Filter举例

@Activate(group = CommonConstants.PROVIDER, order = 1)
public class DubboAccessLogFilter implements Filter {private static final Logger REPORT_LOG = LoggerFactory.getLogger("report");@Overridepublic Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {JSONObject logInfo = new JSONObject();// ...try {// 在日志输出前设置过程数据到MDC// 异步输出日志时,才需要设置MdcUtil.setTraceId();// 可选-同步/异步MdcUtil.setUserId(userId);MdcUtil.setCoachId(coachId);MdcUtil.setApi(api);MdcUtil.setResponseTime(responseTime);MdcUtil.setResponseCode(responseCode);// ...Result result = invoker.invoke(invocation);// ...return result;} finally {REPORT_LOG.info(logInfo.toJSONString());// 资源清理,需要放在日志打印后面MdcUtil.clear();}}
}

使用案例

xxx-class日志异步打印

按追踪维度查询操作日志

按追踪维度查询操作日志

xxx-user日志同步打印

日志同步打印

按api维度查询统计数据

api:"com.xxx.user.client.UserTokenApi/decodeTokenForCoach" and code:"00000"

按api维度查询统计数据

按用户维度查询实操路径

按用户维度查询实操路径

相关文章:

Logback日志异步打印接入指南,输出自定义业务数据

背景 随着应用的请求量上升&#xff0c;日志输出量也会成线性比例的上升&#xff0c;给磁盘IO带来压力与性能瓶颈。应用也遇到了线程池满&#xff0c;是因为大量线程卡在输出日志。为了缓解日志同步打印&#xff0c;会采取异步打印日志。这样会引起日志中的追踪id丢失&#xf…...

将iPad 作为Windows电脑副屏的几种方法(二)

将iPad 作为Windows电脑副屏的几种方法&#xff08;二&#xff09; 1. 前言2. EV 扩展屏2.1 概述2.2 下载、安装、连接教程2.3 遇到的问题和解决方法2.3.1 平板连接不上电脑 3. Twomon SE3.1 概述3.2 下载安装教程 4. 多屏中心&#xff08;GlideX&#xff09;4.1 概述4.2 下载安…...

[word] word表格跨页断开实现教程 #职场发展#媒体

word表格跨页断开实现教程 选中整个word表格 单击鼠标右键&#xff0c;选择“表格属性”选项 切换至“行”标签&#xff0c;找到“允许跨页断行”选项 勾选上“允许跨页断行”&#xff0c;单击“确定”按钮&#xff0c;完成&#xff01; word表格跨页断开实现教程的下载地址&a…...

《Linux运维总结:基于ARM64架构CPU使用docker-compose一键离线部署单机版tendis2.4.2》

总结&#xff1a;整理不易&#xff0c;如果对你有帮助&#xff0c;可否点赞关注一下&#xff1f; 更多详细内容请参考&#xff1a;《Linux运维篇&#xff1a;Linux系统运维指南》 一、部署背景 由于业务系统的特殊性&#xff0c;我们需要面对不同的客户部署业务系统&#xff0…...

【Apache Doris】周FAQ集锦:第 14 期

【Apache Doris】周FAQ集锦&#xff1a;第 14 期 SQL问题数据操作问题运维常见问题其它问题关于社区 欢迎查阅本周的 Apache Doris 社区 FAQ 栏目&#xff01; 在这个栏目中&#xff0c;每周将筛选社区反馈的热门问题和话题&#xff0c;重点回答并进行深入探讨。旨在为广大用户…...

Log4j的原理及应用详解(四)

本系列文章简介&#xff1a; 在软件开发的广阔领域中&#xff0c;日志记录是一项至关重要的活动。它不仅帮助开发者追踪程序的执行流程&#xff0c;还在问题排查、性能监控以及用户行为分析等方面发挥着不可替代的作用。随着软件系统的日益复杂&#xff0c;对日志管理的需求也日…...

农田自动化闸门的结构组成与功能解析

在现代化的农业节水灌溉领域中&#xff0c;农田自动化闸门的应用越来越广泛。它集成了先进的技术&#xff0c;通过自动化控制实现水资源的精准调度和高效利用。本文将围绕农田自动化闸门的结构组成&#xff0c;详细介绍其各个部件的功能和特点。 农田自动化闸门主要由闸门控制箱…...

Python解释器:CPython 解释器

一、什么是python解释器 Python解释器是一种用于执行Python代码的程序。 它将Python源代码转换为机器语言或字节码&#xff0c;从而使计算机能够执行。 1.1 Python解释器分类 1、CPython CPython 是 Python 的主要实现&#xff0c;由 C 语言编写。大多数用户在日常开发中使…...

layui 让table里的下拉框不被遮挡

记录&#xff1a;layui 让table里的下拉框不被遮挡 /* 这个是让table里的下拉框不被遮挡 */ .goods_table .layui-select-title,.goods_table .layui-select-title input{line-height: 28px;height: 28px; }.goods_table .layui-table-cell {overflow: visible !important; }.…...

【性能优化】在大批量数据下使用 HTML+CSS实现走马灯,防止页面卡顿

切换效果 页面结构变化 1.需求背景 项目首页存有一个小的轮播模块,保密原因大概只能这么展示,左侧图片右侧文字,后端一次性返回几百条数据(开发环境下,生产环境只会更多).无法使用分页解决,前端需要懒加载防止页面卡顿 写个小demo演示,如下 2.解决思路 获取到数据后,取第一…...

https和http区别

1、安全性 HTTP信息是明文传输&#xff0c;而HTTPS则通过SSL/TLS协议进行加密传输&#xff0c;确保数据传输的安全性。HTTPS可以验证服务器身份&#xff0c;防止中间人攻击&#xff0c;保护数据的完整性和保密性。 2、端口号 HTTP默认使用80端口&#xff0c;而HTTPS默认使用…...

SD-AI大模型的安装

&#x1f4d1;打牌 &#xff1a; da pai ge的个人主页 &#x1f324;️个人专栏 &#xff1a; da pai ge的博客专栏 ☁️宝剑锋从磨砺出&#xff0c;梅花香自苦寒来 ☁️运维工程师的职责&#xff1a;监…...

UDP-如何实现客户端与服务器端的通信(一对一、一对多、多对一、多对多之间的通信)

Java中提供了DatagramSocket来实现这个功能 1.服务器端的程序 创建Socket&#xff0c;监听6666端口读取来自客户端的“数据包”,创建数据包(通过DatagramPacket实现数据包的创建)接收数据包从数据包中&#xff0c;读取数据(通过recieve()接收数据和send()发送给数据) 代码如下…...

C++那些事之依赖注入

C那些事之依赖注入 最近星球里面有个小伙伴让更新一下依赖注入&#xff0c;于是写出了这篇文章&#xff0c;来从实际的例子讲解&#xff0c;本文会讲解一些原理与实现&#xff0c;完整的实现代码懒人版放在星球中&#xff0c;我们开始正文。 大纲&#xff1a; 直接依赖接口依赖…...

克隆的TrinityCore服务器网速慢卡顿问题的解决(未解决)

一台TrinityCore服务器&#xff0c;采用的是备份克隆安装的方式&#xff0c;在FreeBSD bhyve 中安装Ubuntu&#xff0c;安装细节见如下两篇文档&#xff1a;尝试在FreeBSD 的jail、bhyve里安装TrinityCore-CSDN博客 备份和镜像TrinityCore_魔兽世界 updating auth database...…...

独立站外链如何影响搜索引擎排名?

独立站的外链对搜索引擎排名有着非常重要的影响。简单来说&#xff0c;外链就像是别的网站对你的网站投的信任票。每一条外链都告诉搜索引擎&#xff1a;“这个网站的内容是有价值的&#xff0c;值得推荐。”因此&#xff0c;外链的数量和质量直接影响你的网站在搜索引擎中的排…...

java设计模式:03-04-装饰器模式

装饰器模式&#xff08;Decorator Pattern&#xff09; 装饰器模式&#xff08;Decorator Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其结构。装饰器模式通过创建一个装饰类来包装原有的类&#xff0c;…...

通过splunk web服务将服务器上文件下载到本地

1. 需求说明 工作中经常遇到需要将服务器上的文件下载到本地&#xff0c;但是由于各种网络环境限制&#xff0c;没办法使用winscp或者xftp工具&#xff0c;那么如何将服务器上的文件下载下来呢&#xff1f; 这里提供一种思路: 如果服务器上安装有web服务&#xff0c;可将待下…...

Node.js 路由

Node.js 路由 介绍 Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,它允许开发者使用 JavaScript 编写服务器端代码。Node.js 的一个核心特性是其事件驱动和非阻塞 I/O 模型,这使得它非常适合处理高并发和 I/O 密集型的应用程序。在 Node.js 中,路由是指确定应…...

Adobe国际认证详解-网页设计认证专家行业应用场景解析

在当今数字化时代&#xff0c;网页设计已成为各行各业不可或缺的一环。而网页设计认证专家&#xff0c;作为经过Adobe国际认证体系严格考核的专业人才&#xff0c;正逐渐成为行业内炙手可热的存在。他们凭借深厚的网页设计理论基础和实践经验&#xff0c;为各行各业提供了高质量…...

ESC(ELectronic Stability Control,电子稳定控制系统)

ESC通过实时监测车辆的动态参数&#xff0c;以及车辆轮胎的实际运动状态&#xff0c;通过调节车辆制动系统和发动机输出力&#xff0c;使车辆在紧急或危险情况下保持稳定&#xff0c;防止侧滑和失控。 ESC组成部分 传感器&#xff1a;用于检测车辆的动态参数&#xff0c;如车…...

减分兔搜题-12123学法减分20题目及答案 #媒体#职场发展

对于即将参加驾驶考试的朋友来说&#xff0c;掌握一些经典题目和答案至关重要。今天&#xff0c;我就为大家带来了这样一份干货——20道驾驶考试题目和答案&#xff0c;助你轻松应对考试&#xff01;这些题目不仅包括了考试中常考的内容&#xff0c;还有针对难点和重点的详细解…...

java用freemarker导出word

freemarker导出word 第一步、将word转换为xml格式第二步、将转换后的xml文件修改后缀为ftl后复制到项目 resources 目录下&#xff08;可以自己新建一个文件夹放在文件夹中&#xff09;第三步、格式化xml代码&#xff08;如果问价太大可能会无法格式化&#xff09;这时候需要在…...

CH01_WPF概述

第1章&#xff1a;WPF概述 本章目标 了解Windows图形演化了解WPF高级API了解分辨率无关性概念了解WPF体系结构了解WPF 4.5 WPF概述 ​ 欢迎使用 Windows Presentation Foundation (WPF) 桌面指南&#xff0c;这是一个与分辨率无关的 UI 框架&#xff0c;使用基于矢量的呈现引…...

秒懂设计模式--学习笔记(11)【结构型-享元模式】

目录 10、享元模式10.1 享元模式10.2 举例10.2.1 马赛克10.2.2 游戏地图&#xff08;以草原地图作为范例&#xff09; 10.3 总结 10、享元模式 10.1 享元模式 “享元”则是共享元件的意思享元模式的英文flyweight是轻量级的意思&#xff0c;这就意味着享元模式能使程序变得更…...

Python爬虫——1爬虫基础(一步一步慢慢来)

一、爬虫是什么&#xff1f; &#xff08;spider&#xff09; Python 爬虫是利用编程语言 Python 来获取互联网上的数据的技术。它可以自动化地访问网页、提取信息并进行数据处理。以下是Python爬虫的基础知识和步骤&#xff1a; 主要特点和功能&#xff1a; 自动化浏览&#…...

【js自学打卡9】抛出异常 / 幂计算 / 发布订阅 / map小知识点

1. 抛出异常的写法 抛出一个简单的字符串错误 throw Error2; // 抛出一个字符串抛出一个Error对象 throw new Error(出错了&#xff01;);抛出一个自定义错误对象 function UserError(message) {this.message message;this.name "UserError"; } throw new User…...

ArcGIS Pro SDK (九)几何 7 多点

ArcGIS Pro SDK &#xff08;九&#xff09;几何 7 多点 文章目录 ArcGIS Pro SDK &#xff08;九&#xff09;几何 7 多点1 构造多点 - 从映射点的枚举2 构造多点 - 使用 MultipointBuilderEx3 修改多点的点4 从多点检索点、2D 坐标、3D 坐标 环境&#xff1a;Visual Studio 2…...

服务器注意事项

1. 远程服务器不允许关机&#xff0c;只能重启&#xff1b; 2. 重启服务器应关闭服务&#xff1b; 3. 不要在服务器访问高峰运行高负载命令&#xff1b; 4. 远程配置防火墙是不要把自己踢出服务器&#xff1b; 5. 制定合理的密码规范并定期更新&#xff1b; 6. 合理分配权…...

学生信息管理系统设计

学生信息管理系统的设计是一个综合性的项目&#xff0c;涉及到数据的存储、检索、更新和删除等基本操作&#xff0c;同时也需要考虑系统的易用性、安全性和扩展性。以下是一些关键步骤和要素&#xff0c;用于指导设计这样一个系统&#xff1a; 1. 需求分析 目标用户&#xff…...

设计一个网页要多少钱/太原seo优化公司

https://wiki.videolan.org/AndroidCompile/...

网站建设广州公司哪家好/独立站谷歌seo

很久没有在博客写东西了&#xff0c;这段时间也比较累&#xff0c;工作比较忙&#xff0c;还有就是自己这段时间太懒了。越是不写东西&#xff0c;越是不思考&#xff0c;感觉大脑越是空空如也。 大概整理一下自己的2017年&#xff0c;主要是一个字 &#xff1a; 变。 从一个…...

淘宝上网站开发/nba最新交易新闻

1.将一个给定的整型数组转置输出&#xff0c; 源数组为&#xff1a;1 2 3 4 5 6转置之后输出的数组为&#xff1a;6 5 4 3 2 1 刚看到题目的时候没多想&#xff0c;只想着能倒着输出就好&#xff08;正确代码错误想法&#xff09; public static void main(String[] args){int…...

网站做导航设计的作用是什么意思/昆明百度推广开户

前言 最近 以为同事在调试 类似如下代码片段的时候 使用了 mapPartitionsWithIndex, 来进行输出上下文信息的调试 业务代码中 一系列的 transformations 的处理之后, 使用了 sortByKey take 进行 "分页" 处理 然后 她在 这一系列的 transformations 操作中间增…...

南京高端网站建设工作室/百度搜索引擎推广步骤

web应用程序 本质 socket服务端 浏览器本质是一个socket客户端1. 服务器程序 socket请求 接受HTTP请求&#xff0c;发送HTTP响应。比较底层&#xff0c;繁琐&#xff0c;有专用的服务器软件&#xff0c;如&#xff1a;Apache Nginx2. 应用程序&#xff0c;实现具体逻辑WSGI&…...

淘宝天猫优惠券网站怎么做/百度开户推广多少钱

1、打开Internert信息管理查看IIS是否启动&#xff0c;且默认网站时候已经开启&#xff1b; 2、打开http://127.0.0.1 看是否能访问IIS的默认网页&#xff0c;能访问则说明IIS已经成功安装到电脑上&#xff0c;可能是无法解析localhost&#xff1b; 3、开始--命令&#xff08…...