buguge - Keep it simple,stupid

知识就是力量,但更重要的,是运用知识的能力why buguge?

导航

程序日志优化:精准捕获与日志分级,践行数字低碳

面对系统每日产生的海量日志,我们的一次小小技术优化,不仅是提升效率,更是一次实实在在的“低碳”实践。本文将以一条具体的 org.apache.http.conn.ConnectTimeoutException 异常日志为例,展示如何通过技术手段,在保障系统可观测性的同时,为节能减碳贡献力量。


先贴出来这个timeout异常log,看看你需要几次下滑屏幕?

点击查看代码
2025-10-22 11:00:05.191 [TID:d2faa69abf014567ad1b23fcd34f8967.844.17611020000360091] [DubboServerHandler-10.*.1.110:20890-thread-197] ERROR c.e.c.p.m.l.levyimpl.own.LevySignProviderApiByOWN:? - *****【自有服务商】 签约调服务商查询接口,异常:{}java.lang.RuntimeException: org.apache.http.conn.ConnectTimeoutException: Connect to 47.*.99.98:8280 [/47.*.99.98] failed: connect timed out
    at com.emax.channel.provider.modules.levyprovider.util.HttpClientHelper.httpClientPost(HttpClientHelper.java:403)
    at com.emax.channel.provider.modules.levyprovider.util.HttpClientHelper.httpClientPost(HttpClientHelper.java:435)
    at com.emax.channel.provider.modules.levyprovider.levyimpl.own.LevySignProviderApiByOWN.querySign(LevySignProviderApiByOWN.java:224)
    at com.emax.channel.provider.modules.levyprovider.levyimpl.own.LevyServiceProviderApiByOWN.querySign(LevyServiceProviderApiByOWN.java:691)
    at com.emax.channel.provider.modules.levyprovider.levyimpl.own.LevyServiceProviderApiByOWN$$FastClassBySpringCGLIB$$1465a46f.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)
    at com.emax.channel.provider.modules.levyprovider.levyimpl.own.LevyServiceProviderApiByOWN$$EnhancerBySpringCGLIB$$cc086de3.querySign(<generated>)
    at com.emax.channel.provider.modules.levyprovider.levyimpl._route.LevyChannelRouteServiceImpl.querySign(LevyChannelRouteServiceImpl.java:330)
    at com.emax.channel.provider.modules.levyprovider.levyimpl._route.LevyChannelRouteServiceImpl$$FastClassBySpringCGLIB$$c67fd737.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)
    at com.emax.channel.provider.modules.levyprovider.levyimpl._route.LevyChannelRouteServiceImpl$$EnhancerBySpringCGLIB$$4b092e13.querySign(<generated>)
    at com.emax.channel.provider.modules.levySign.service.LevySignBizService.queryLevySignStatus(LevySignBizService.java:121)
    at com.emax.channel.provider.modules.levySign.provider.LevySignServiceImpl.querySign(LevySignServiceImpl.java:158)
    at com.emax.channel.provider.modules.levySign.provider.LevySignServiceImpl$$FastClassBySpringCGLIB$$f64e351d.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
    at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:88)
    at com.emax.zhenghe.common.aspect.LogExecutionInterceptor.logExecution(LogExecutionInterceptor.java:55)
    at sun.reflect.GeneratedMethodAccessor797.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633)
    at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)
    at com.emax.channel.provider.modules.levySign.provider.LevySignServiceImpl$$EnhancerBySpringCGLIB$$b352fcad.querySign(<generated>)
    at com.emax.channel.rpcapi.levySign.service.LevySignServiceDubboWrap130.invokeMethod(LevySignServiceDubboWrap130.java)
    at org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory$1.doInvoke(JavassistProxyFactory.java:73)
    at org.apache.dubbo.rpc.proxy.AbstractProxyInvoker.invoke(AbstractProxyInvoker.java:100)
    at org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker.invoke(DelegateProviderMetaDataInvoker.java:55)
    at org.apache.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:56)
    at org.apache.dubbo.rpc.filter.ClassLoaderCallbackFilter.invoke(ClassLoaderCallbackFilter.java:38)
    at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:327)
    at com.emax.zhenghe.common.filters.ProviderExceptionFilter.invoke(ProviderExceptionFilter.java:32)
    at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:327)
    at org.apache.dubbo.rpc.protocol.dubbo.filter.TraceFilter.invoke(TraceFilter.java:79)
    at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:327)
    at org.apache.dubbo.rpc.filter.TimeoutFilter.invoke(TimeoutFilter.java:44)
    at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:327)
    at com.alibaba.csp.sentinel.adapter.dubbo3.SentinelDubboProviderFilter.invoke(SentinelDubboProviderFilter.java:85)
    at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:327)
    at com.emax.zhenghe.common.filters.ProviderRequestLogFilter.invoke(ProviderRequestLogFilter.java:60)
    at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:327)
    at com.serviceshare.principal.dubbo.filter.ProviderPrincipalFilter.invoke(ProviderPrincipalFilter.java:50)
    at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:327)
    at org.apache.dubbo.monitor.support.MonitorFilter.$sw$original$invoke$1vamrv0(MonitorFilter.java:100)
    at org.apache.dubbo.monitor.support.MonitorFilter.$sw$original$invoke$1vamrv0$accessor$$sw$p4vq621(MonitorFilter.java)
    at org.apache.dubbo.monitor.support.MonitorFilter$$sw$auxiliary$61t58p2.call(Unknown Source)
    at org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstMethodsInter.intercept(InstMethodsInter.java:86)
    at org.apache.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java)
    at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:327)
    at org.apache.dubbo.rpc.filter.ExceptionFilter.invoke(ExceptionFilter.java:54)
    at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:327)
    at org.apache.dubbo.rpc.filter.GenericFilter.invoke(GenericFilter.java:192)
    at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:327)
    at org.apache.dubbo.rpc.filter.ClassLoaderFilter.invoke(ClassLoaderFilter.java:54)
    at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:327)
    at org.apache.dubbo.rpc.filter.EchoFilter.invoke(EchoFilter.java:41)
    at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:327)
    at org.apache.dubbo.rpc.filter.ProfilerServerFilter.invoke(ProfilerServerFilter.java:58)
    at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:327)
    at org.apache.dubbo.rpc.filter.ContextFilter.invoke(ContextFilter.java:133)
    at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:327)
    at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CallbackRegistrationInvoker.invoke(FilterChainBuilder.java:194)
    at org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol$1.reply(DubboProtocol.java:156)
    at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.handleRequest(HeaderExchangeHandler.java:102)
    at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.received(HeaderExchangeHandler.java:177)
    at org.apache.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:53)
    at org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:62)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.dubbo.common.threadlocal.InternalRunnable.run(InternalRunnable.java:41)
    at java.lang.Thread.run(Thread.java:750)
Caused by: org.apache.http.conn.ConnectTimeoutException: Connect to 47.*.99.98:8280 [/47.*.99.98] failed: connect timed out
    at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:151)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:376)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:393)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
    at org.apache.http.impl.client.InternalHttpClient.$sw$original$doExecute$7gb7dq1(InternalHttpClient.java:185)
    at org.apache.http.impl.client.InternalHttpClient.$sw$original$doExecute$7gb7dq1$accessor$$sw$l56slt2(InternalHttpClient.java)
    at org.apache.http.impl.client.InternalHttpClient$$sw$auxiliary$67oq2v1.call(Unknown Source)
    at org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstMethodsInter.intercept(InstMethodsInter.java:86)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
    at com.emax.channel.provider.modules.levyprovider.util.HttpClientHelper.httpClientPost(HttpClientHelper.java:393)
    ... 93 common frames omitted
Caused by: java.net.SocketTimeoutException: connect timed out
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    at java.net.Socket.connect(Socket.java:607)
    at org.apache.http.conn.socket.PlainConnectionSocketFactory.connectSocket(PlainConnectionSocketFactory.java:75)
    at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142)
    ... 107 common frames omitted

海量的日志,尤其是冗长的异常堆栈,不仅占据大量存储空间,其写入过程也持续消耗着计算和电力资源。每一次磁盘I/O操作,都关联着数据中心的能耗。据研究,即便是线上办公工具的使用,其碳减排贡献也相当可观,一次线上会议相比线下出行就能减少可观的碳排放。我们的系统日志优化,也正是遵循类似的“低碳”逻辑——减少不必要的数据输出,就是减少能源消耗

优化前的代码对所有的异常“一视同仁”,打印完整的堆栈轨迹,导致单次异常日志就可能超过100行。若此类异常每日发生数百次,其累积的日志量及其背后的存储与处理能耗不容小觑。

} catch (Exception e) {
    log.error("*****{} 签约调服务商查询接口,异常:{}", BUSI_NAME, e); // 无论何种异常,均打印完整错误堆栈
    signResultVo.setResultMsg("签约查询异常");
}

优化后的代码则对连接超时这类已知的、相对常见的异常进行了“低碳”化处理:降低日志级别为 WARN,并仅记录关键信息,避免输出冗长的堆栈轨迹。

} catch (Exception e) {
    // 单独处理连接超时异常,践行日志“低碳”化:减少不必要的信息输出,降低存储与处理能耗
    if (e instanceof ConnectTimeoutException || e.getCause() instanceof org.apache.http.conn.ConnectTimeoutException) {
        log.warn("*****{} 签约调服务商查询接口超时,levy={}-{} : {}", BUSI_NAME,
                channelConfig.getLevyCode(), channelConfig.getLevyName(),
                ExceptionUtils.getMessage(e)); // 关键信息一目了然,摒弃冗余堆栈
    } else {
        log.error("*****{} 签约调服务商查询接口,异常:{}", BUSI_NAME, e); // 其他异常仍按错误级别完整记录
    }
    signResultVo.setResultMsg("签约查询异常");
}

低碳成效速览

下表清晰展示了本次优化在“低碳”维度上的直接收益:

对比项 优化前 (单次异常) 优化后 (单次异常) 低碳收益分析
日志行数 约 100+ 行 1行 日志体积减少超过99%,直接降低了存储空间占用和后续处理所需的计算资源。
存储占用 巨大 极小 每日可节省大量磁盘空间,意味着数据中心硬盘阵列的能耗得以降低。
I/O 负载 高(写入大量数据) 极低 显著减少磁盘写入操作,降低系统I/O压力,间接节约了电力。
核心信息 淹没在堆栈细节中 聚焦于异常原因与服务商 保持了关键信息(何种异常、哪个服务商),满足了监控与排查的基本需求。

通过单元测试验证,优化后,原本冗长的错误日志被精简为一行清晰的警告信息:

// 优化前:超过100行的堆栈跟踪
// 优化后:
2025-10-22 14:29:58,754 WARN ... - *****【自有服务商】 签约调服务商查询接口超时,levy=XXX-XXX : ConnectTimeoutException: Connect to ... timed out

总结:代码优化亦是环保行动

本次优化巧妙地将“低碳”理念融入技术实践:

  • 精准:对超时异常进行差异化处理,避免信息冗余。
  • 高效:用最少的日志承载最关键的信息,提升运维效率。
  • 绿色:通过大幅削减日志量,直接降低了系统的存储成本能源消耗

这正印证了“低碳”并非遥不可及的口号,它同样体现在我们编写的每一行代码、每一次针对性的技术优化中。当数百次的异常日志从每天占用数MB空间锐减至几KB时,我们为减少数字世界的“碳足迹”做出了实实在在的努力。

希望这个案例能启发大家,在追求系统稳定高效的同时,积极发现并践行更多的技术“低碳”可能性。

posted on 2025-10-22 20:47  buguge  阅读(0)  评论(0)    收藏  举报