| <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Apache Dubbo – 可观测性</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/observability/</link><description>Recent content in 可观测性 on Apache Dubbo</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><atom:link href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/observability/index.xml" rel="self" type="application/rss+xml"/><item><title>Overview: Metrics</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/observability/meter/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/observability/meter/</guid><description> |
| <h2 id="概述">概述</h2> |
| <p>Dubbo Metrics 的总体设计请参考 <a href="https://dubbo.apache.org/zh-cn/overview/reference/proposals/metrics/">可观测性 Metrics Proposal</a>。</p> |
| <p>以下是 Dubbo Java 相关的具体实现与使用方式讲解。</p> |
| <h2 id="使用方式">使用方式</h2> |
| <p>要为 Dubbo 进程开启指标采集,需要在项目中引入相关依赖并增加配置。以 Spring Boot 项目为例,增加以下 spring-boot-starter 依赖到项目中,即会自动开启指标采集。</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#586e75">&lt;!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-metrics-prometheus --&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dependency&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;groupId&gt;</span>org.apache.dubbo<span style="color:#268bd2">&lt;/groupId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;artifactId&gt;</span>dubbo-spring-boot-observability-starter<span style="color:#268bd2">&lt;/artifactId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;version&gt;</span>3.2.0<span style="color:#268bd2">&lt;/version&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/dependency&gt;</span> |
| </span></span></code></pre></div><ul> |
| <li>完整示例请参见 <a href="https://github.com/apache/dubbo-samples/tree/master/4-governance/dubbo-samples-metrics-spring-boot" target="_blank">dubbo-samples-metrics-spring-boot</a></li> |
| <li>完整配置参数请参见 <a href="../../../reference-manual/config/properties/#metrics">Metrics 配置项手册</a></li> |
| </ul> |
| <h2 id="实现原理解析">实现原理解析</h2> |
| <h3 id="代码结构与工作流程">代码结构与工作流程</h3> |
| <ul> |
| <li>移除原来与 Metrics 相关的类</li> |
| <li>创建新模块 dubbo-metrics/dubbo-metrics-api、dubbo-metrics/dubbo-metrics-prometheus,MetricsConfig 作为该模块的配置类</li> |
| <li>使用micrometer,在Collector中使用基本类型代表指标,如Long、Double等,并在dubbo-metrics-api中引入micrometer,由micrometer对内部指标进行转换</li> |
| </ul> |
| <p>以下是 Dubbo 实现中的关键组件及数据流转过程</p> |
| <p><img src="https://dubbo.apache.org/imgs/docs3-v2/java-sdk/observability/dataflow.png" alt="img.png"></p> |
| <h3 id="指标上报接口">指标上报接口</h3> |
| <p>根据上图架构,指标接口是 Dubbo 对外暴露指标数据的出口,以下是指标接口的具体定义:</p> |
| <blockquote> |
| <p>另外,该 Service 还作为一些 <a href="https://dubbo.apache.org/zh-cn/overview/reference/proposals/heuristic-flow-control/">智能自适应流量调度算法</a> 的数据来源</p> |
| </blockquote> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">interface</span> <span style="color:#268bd2">MetricsService</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">/** |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * Default {@link MetricsService} extension name. |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> */</span> |
| </span></span><span style="display:flex;"><span> String DEFAULT_EXTENSION_NAME <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;default&#34;</span><span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">/** |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * The contract version of {@link MetricsService}, the future update must make sure compatible. |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> */</span> |
| </span></span><span style="display:flex;"><span> String VERSION <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;1.0.0&#34;</span><span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">/** |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * Get metrics by prefixes |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * @param categories categories |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * @return metrics - key=MetricCategory value=MetricsEntityList |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> */</span> |
| </span></span><span style="display:flex;"><span> Map<span style="color:#719e07">&lt;</span>MetricsCategory<span style="color:#719e07">,</span> List<span style="color:#719e07">&lt;</span>MetricsEntity<span style="color:#719e07">&gt;&gt;</span> <span style="color:#268bd2">getMetricsByCategories</span><span style="color:#719e07">(</span>List<span style="color:#719e07">&lt;</span>MetricsCategory<span style="color:#719e07">&gt;</span> categories<span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">/** |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * Get metrics by interface and prefixes |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * @param serviceUniqueName serviceUniqueName (eg.group/interfaceName:version) |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * @param categories categories |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * @return metrics - key=MetricCategory value=MetricsEntityList |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> */</span> |
| </span></span><span style="display:flex;"><span> Map<span style="color:#719e07">&lt;</span>MetricsCategory<span style="color:#719e07">,</span> List<span style="color:#719e07">&lt;</span>MetricsEntity<span style="color:#719e07">&gt;&gt;</span> <span style="color:#268bd2">getMetricsByCategories</span><span style="color:#719e07">(</span>String serviceUniqueName<span style="color:#719e07">,</span> List<span style="color:#719e07">&lt;</span>MetricsCategory<span style="color:#719e07">&gt;</span> categories<span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">/** |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * Get metrics by interface、method and prefixes |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * @param serviceUniqueName serviceUniqueName (eg.group/interfaceName:version) |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * @param methodName methodName |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * @param parameterTypes method parameter types |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * @param categories categories |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * @return metrics - key=MetricCategory value=MetricsEntityList |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> */</span> |
| </span></span><span style="display:flex;"><span> Map<span style="color:#719e07">&lt;</span>MetricsCategory<span style="color:#719e07">,</span> List<span style="color:#719e07">&lt;</span>MetricsEntity<span style="color:#719e07">&gt;&gt;</span> <span style="color:#268bd2">getMetricsByCategories</span><span style="color:#719e07">(</span>String serviceUniqueName<span style="color:#719e07">,</span> String methodName<span style="color:#719e07">,</span> Class<span style="color:#719e07">&lt;?&gt;[]</span> parameterTypes<span style="color:#719e07">,</span> List<span style="color:#719e07">&lt;</span>MetricsCategory<span style="color:#719e07">&gt;</span> categories<span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">}</span> |
| </span></span></code></pre></div><p>其中 MetricsCategory 设计如下:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">enum</span> MetricsCategory <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> RT<span style="color:#719e07">,</span> |
| </span></span><span style="display:flex;"><span> QPS<span style="color:#719e07">,</span> |
| </span></span><span style="display:flex;"><span> REQUESTS<span style="color:#719e07">,</span> |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">}</span> |
| </span></span></code></pre></div><p>MetricsEntity 设计如下</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">MetricsEntity</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> String name<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> Map<span style="color:#719e07">&lt;</span>String<span style="color:#719e07">,</span> String<span style="color:#719e07">&gt;</span> tags<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> MetricsCategory category<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> Object value<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">}</span> |
| </span></span></code></pre></div><h3 id="指标采集埋点">指标采集埋点</h3> |
| <p>Dubbo 是通过扩展 Filter SPI 扩展点实现对请求调用指标进行拦截的,目前在消费端和提供端分别增加了 Filter 扩展实现</p> |
| <ul> |
| <li>MetricsFilter 提供端请求指标埋点</li> |
| <li>MetricsClusterFilter 消费端请求指标埋点</li> |
| </ul> |
| <p>以下是 MetricsFilter 的实现源码,注意 try-catch-finally 处理。</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">@Activate</span><span style="color:#719e07">(</span>group <span style="color:#719e07">=</span> PROVIDER<span style="color:#719e07">,</span> order <span style="color:#719e07">=</span> <span style="color:#719e07">-</span>1<span style="color:#719e07">)</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">MetricsFilter</span> <span style="color:#268bd2">implements</span> Filter<span style="color:#719e07">,</span> ScopeModelAware <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Override</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> Result <span style="color:#268bd2">invoke</span><span style="color:#719e07">(</span>Invoker<span style="color:#719e07">&lt;?&gt;</span> invoker<span style="color:#719e07">,</span> Invocation invocation<span style="color:#719e07">)</span> <span style="color:#268bd2">throws</span> RpcException <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> collector<span style="color:#719e07">.</span>increaseTotalRequests<span style="color:#719e07">(</span>interfaceName<span style="color:#719e07">,</span> methodName<span style="color:#719e07">,</span> group<span style="color:#719e07">,</span> version<span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span> collector<span style="color:#719e07">.</span>increaseProcessingRequests<span style="color:#719e07">(</span>interfaceName<span style="color:#719e07">,</span> methodName<span style="color:#719e07">,</span> group<span style="color:#719e07">,</span> version<span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span> Long startTime <span style="color:#719e07">=</span> System<span style="color:#719e07">.</span>currentTimeMillis<span style="color:#719e07">();</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">try</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> Result invoke <span style="color:#719e07">=</span> invoker<span style="color:#719e07">.</span>invoke<span style="color:#719e07">(</span>invocation<span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span> collector<span style="color:#719e07">.</span>increaseSucceedRequests<span style="color:#719e07">(</span>interfaceName<span style="color:#719e07">,</span> methodName<span style="color:#719e07">,</span> group<span style="color:#719e07">,</span> version<span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> invoke<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">}</span> <span style="color:#719e07">catch</span> <span style="color:#719e07">(</span>RpcException e<span style="color:#719e07">)</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> collector<span style="color:#719e07">.</span>increaseFailedRequests<span style="color:#719e07">(</span>interfaceName<span style="color:#719e07">,</span> methodName<span style="color:#719e07">,</span> group<span style="color:#719e07">,</span> version<span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">throw</span> e<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">}</span> <span style="color:#719e07">finally</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> Long endTime <span style="color:#719e07">=</span> System<span style="color:#719e07">.</span>currentTimeMillis<span style="color:#719e07">();</span> |
| </span></span><span style="display:flex;"><span> Long rt <span style="color:#719e07">=</span> endTime <span style="color:#719e07">-</span> startTime<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> collector<span style="color:#719e07">.</span>addRT<span style="color:#719e07">(</span>interfaceName<span style="color:#719e07">,</span> methodName<span style="color:#719e07">,</span> group<span style="color:#719e07">,</span> version<span style="color:#719e07">,</span> rt<span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span> collector<span style="color:#719e07">.</span>decreaseProcessingRequests<span style="color:#719e07">(</span>interfaceName<span style="color:#719e07">,</span> methodName<span style="color:#719e07">,</span> group<span style="color:#719e07">,</span> version<span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">}</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">}</span> |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">}</span> |
| </span></span></code></pre></div><h3 id="指标统计单位">指标统计单位</h3> |
| <p>以下五个属性是指标统计的基本单位(应用、服务、方法的组合),也是源代码 MetricsCollector 中 Map 数据结构的 key</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">MethodMetric</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> String applicationName<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> String interfaceName<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> String methodName<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> String group<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> String version<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">}</span> |
| </span></span></code></pre></div><h3 id="基础指标">基础指标</h3> |
| <p>dubbo-common 模块下的 MetricsCollector 负责存储所有指标数据</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">DefaultMetricsCollector</span> <span style="color:#268bd2">implements</span> MetricsCollector <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> Boolean collectEnabled <span style="color:#719e07">=</span> <span style="color:#cb4b16">false</span><span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> List<span style="color:#719e07">&lt;</span>MetricsListener<span style="color:#719e07">&gt;</span> listeners <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ArrayList<span style="color:#719e07">&lt;&gt;();</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> ApplicationModel applicationModel<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> String applicationName<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> Map<span style="color:#719e07">&lt;</span>MethodMetric<span style="color:#719e07">,</span> AtomicLong<span style="color:#719e07">&gt;</span> totalRequests <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ConcurrentHashMap<span style="color:#719e07">&lt;&gt;();</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> Map<span style="color:#719e07">&lt;</span>MethodMetric<span style="color:#719e07">,</span> AtomicLong<span style="color:#719e07">&gt;</span> succeedRequests <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ConcurrentHashMap<span style="color:#719e07">&lt;&gt;();</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> Map<span style="color:#719e07">&lt;</span>MethodMetric<span style="color:#719e07">,</span> AtomicLong<span style="color:#719e07">&gt;</span> failedRequests <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ConcurrentHashMap<span style="color:#719e07">&lt;&gt;();</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> Map<span style="color:#719e07">&lt;</span>MethodMetric<span style="color:#719e07">,</span> AtomicLong<span style="color:#719e07">&gt;</span> processingRequests <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ConcurrentHashMap<span style="color:#719e07">&lt;&gt;();</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> Map<span style="color:#719e07">&lt;</span>MethodMetric<span style="color:#719e07">,</span> AtomicLong<span style="color:#719e07">&gt;</span> lastRT <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ConcurrentHashMap<span style="color:#719e07">&lt;&gt;();</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> Map<span style="color:#719e07">&lt;</span>MethodMetric<span style="color:#719e07">,</span> LongAccumulator<span style="color:#719e07">&gt;</span> minRT <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ConcurrentHashMap<span style="color:#719e07">&lt;&gt;();</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> Map<span style="color:#719e07">&lt;</span>MethodMetric<span style="color:#719e07">,</span> LongAccumulator<span style="color:#719e07">&gt;</span> maxRT <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ConcurrentHashMap<span style="color:#719e07">&lt;&gt;();</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> Map<span style="color:#719e07">&lt;</span>MethodMetric<span style="color:#719e07">,</span> AtomicLong<span style="color:#719e07">&gt;</span> avgRT <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ConcurrentHashMap<span style="color:#719e07">&lt;&gt;();</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> Map<span style="color:#719e07">&lt;</span>MethodMetric<span style="color:#719e07">,</span> AtomicLong<span style="color:#719e07">&gt;</span> totalRT <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ConcurrentHashMap<span style="color:#719e07">&lt;&gt;();</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> Map<span style="color:#719e07">&lt;</span>MethodMetric<span style="color:#719e07">,</span> AtomicLong<span style="color:#719e07">&gt;</span> rtCount <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ConcurrentHashMap<span style="color:#719e07">&lt;&gt;();</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">}</span> |
| </span></span></code></pre></div><h3 id="本地指标聚合">本地指标聚合</h3> |
| <p>本地聚合指将一些简单的指标通过计算获取各分位数指标的过程。</p> |
| <h4 id="开启本地聚合">开启本地聚合</h4> |
| <p>收集指标时,默认只收集基础指标,而一些单机聚合指标则需要开启服务柔性或者本地聚合后另起线程计算。</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-properties" data-lang="properties"><span style="display:flex;"><span>dubbo.metrics.enable<span style="color:#719e07">=</span><span style="color:#2aa198">true</span> |
| </span></span></code></pre></div><p>另外,还可以设置一些更多的指标</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-properties" data-lang="properties"><span style="display:flex;"><span>dubbo.metrics.aggregation.enable<span style="color:#719e07">=</span><span style="color:#2aa198">true</span> |
| </span></span><span style="display:flex;"><span>dubbo.metrics.aggregation.bucket-num<span style="color:#719e07">=</span><span style="color:#2aa198">5</span> |
| </span></span><span style="display:flex;"><span>dubbo.metrics.aggregation.time-window-seconds<span style="color:#719e07">=</span><span style="color:#2aa198">10</span> |
| </span></span></code></pre></div><h4 id="具体指标">具体指标</h4> |
| <p><a href="https://dubbo.apache.org/zh-cn/overview/reference/metrics/standard_metrics/">具体指标</a> 请参考 Dubbo Metrics 总体设计文档。</p> |
| <h4 id="聚合收集器实现">聚合收集器实现</h4> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">AggregateMetricsCollector</span> <span style="color:#268bd2">implements</span> MetricsCollector<span style="color:#719e07">,</span> MetricsListener <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#dc322f">int</span> bucketNum<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#dc322f">int</span> timeWindowSeconds<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> Map<span style="color:#719e07">&lt;</span>MethodMetric<span style="color:#719e07">,</span> TimeWindowCounter<span style="color:#719e07">&gt;</span> totalRequests <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ConcurrentHashMap<span style="color:#719e07">&lt;&gt;();</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> Map<span style="color:#719e07">&lt;</span>MethodMetric<span style="color:#719e07">,</span> TimeWindowCounter<span style="color:#719e07">&gt;</span> succeedRequests <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ConcurrentHashMap<span style="color:#719e07">&lt;&gt;();</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> Map<span style="color:#719e07">&lt;</span>MethodMetric<span style="color:#719e07">,</span> TimeWindowCounter<span style="color:#719e07">&gt;</span> failedRequests <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ConcurrentHashMap<span style="color:#719e07">&lt;&gt;();</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> Map<span style="color:#719e07">&lt;</span>MethodMetric<span style="color:#719e07">,</span> TimeWindowCounter<span style="color:#719e07">&gt;</span> qps <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ConcurrentHashMap<span style="color:#719e07">&lt;&gt;();</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> Map<span style="color:#719e07">&lt;</span>MethodMetric<span style="color:#719e07">,</span> TimeWindowQuantile<span style="color:#719e07">&gt;</span> rt <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ConcurrentHashMap<span style="color:#719e07">&lt;&gt;();</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> ApplicationModel applicationModel<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">static</span> <span style="color:#268bd2">final</span> Integer DEFAULT_COMPRESSION <span style="color:#719e07">=</span> 100<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">static</span> <span style="color:#268bd2">final</span> Integer DEFAULT_BUCKET_NUM <span style="color:#719e07">=</span> 10<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">static</span> <span style="color:#268bd2">final</span> Integer DEFAULT_TIME_WINDOW_SECONDS <span style="color:#719e07">=</span> 120<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">//在构造函数中解析配置信息 |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"></span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#268bd2">AggregateMetricsCollector</span><span style="color:#719e07">(</span>ApplicationModel applicationModel<span style="color:#719e07">)</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">this</span><span style="color:#719e07">.</span>applicationModel <span style="color:#719e07">=</span> applicationModel<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> ConfigManager configManager <span style="color:#719e07">=</span> applicationModel<span style="color:#719e07">.</span>getApplicationConfigManager<span style="color:#719e07">();</span> |
| </span></span><span style="display:flex;"><span> MetricsConfig config <span style="color:#719e07">=</span> configManager<span style="color:#719e07">.</span>getMetrics<span style="color:#719e07">().</span>orElse<span style="color:#719e07">(</span><span style="color:#cb4b16">null</span><span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">if</span> <span style="color:#719e07">(</span>config <span style="color:#719e07">!=</span> <span style="color:#cb4b16">null</span> <span style="color:#719e07">&amp;&amp;</span> config<span style="color:#719e07">.</span>getAggregation<span style="color:#719e07">()</span> <span style="color:#719e07">!=</span> <span style="color:#cb4b16">null</span> <span style="color:#719e07">&amp;&amp;</span> Boolean<span style="color:#719e07">.</span>TRUE<span style="color:#719e07">.</span>equals<span style="color:#719e07">(</span>config<span style="color:#719e07">.</span>getAggregation<span style="color:#719e07">().</span>getEnabled<span style="color:#719e07">()))</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// only registered when aggregation is enabled. |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"></span> registerListener<span style="color:#719e07">();</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> AggregationConfig aggregation <span style="color:#719e07">=</span> config<span style="color:#719e07">.</span>getAggregation<span style="color:#719e07">();</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">this</span><span style="color:#719e07">.</span>bucketNum <span style="color:#719e07">=</span> aggregation<span style="color:#719e07">.</span>getBucketNum<span style="color:#719e07">()</span> <span style="color:#719e07">==</span> <span style="color:#cb4b16">null</span> <span style="color:#719e07">?</span> DEFAULT_BUCKET_NUM <span style="color:#719e07">:</span> aggregation<span style="color:#719e07">.</span>getBucketNum<span style="color:#719e07">();</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">this</span><span style="color:#719e07">.</span>timeWindowSeconds <span style="color:#719e07">=</span> aggregation<span style="color:#719e07">.</span>getTimeWindowSeconds<span style="color:#719e07">()</span> <span style="color:#719e07">==</span> <span style="color:#cb4b16">null</span> <span style="color:#719e07">?</span> DEFAULT_TIME_WINDOW_SECONDS <span style="color:#719e07">:</span> aggregation<span style="color:#719e07">.</span>getTimeWindowSeconds<span style="color:#719e07">();</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">}</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">}</span> |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">}</span> |
| </span></span></code></pre></div><p>如果开启了本地聚合,则通过 spring 的 BeanFactory 添加监听,将 AggregateMetricsCollector 与 DefaultMetricsCollector 绑定,实现一种生存者消费者的模式,DefaultMetricsCollector 中使用监听器列表,方便扩展</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">private</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">registerListener</span><span style="color:#719e07">()</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> applicationModel<span style="color:#719e07">.</span>getBeanFactory<span style="color:#719e07">().</span>getBean<span style="color:#719e07">(</span>DefaultMetricsCollector<span style="color:#719e07">.</span>class<span style="color:#719e07">).</span>addListener<span style="color:#719e07">(</span><span style="color:#719e07">this</span><span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">}</span> |
| </span></span></code></pre></div><h3 id="指标聚合原理">指标聚合原理</h3> |
| <p>滑动窗口 |
| 假设我们初始有6个bucket,每个窗口时间设置为2分钟 |
| 每次写入指标数据时,会将数据分别写入6个bucket内,每隔两分钟移动一个bucket并且清除原来bucket内的数据 |
| 读取指标时,读取当前current指向的bucket,以达到滑动窗口的效果 |
| 具体如下图所示,实现了当前 bucket 内存储了配置中设置的 bucket 生命周期内的数据,即近期数据 |
| <img src="https://dubbo.apache.org/imgs/docs3-v2/java-sdk/observability/aggre.png" alt="img_1.png"></p> |
| <p>在每个bucket内,使用<strong>TDigest 算法</strong>计算分位数指标</p> |
| <blockquote> |
| <p><strong>TDigest 算法</strong>(极端分位精确度高,如p1 p99,中间分位精确度低,如p50),相关资料如下</p> |
| <ul> |
| <li><a href="https://op8867555.github.io/posts/2018-04-09-tdigest.html">https://op8867555.github.io/posts/2018-04-09-tdigest.html</a></li> |
| <li><a href="https://blog.csdn.net/csdnnews/article/details/116246540">https://blog.csdn.net/csdnnews/article/details/116246540</a></li> |
| <li>开源实现:https://github.com/tdunning/t-digest</li> |
| </ul> |
| </blockquote> |
| <p>代码实现如下,除了 TimeWindowQuantile 用来计算分位数指标外,另外提供了 TimeWindowCounter 来收集时间区间内的指标数量</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">TimeWindowQuantile</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> <span style="color:#dc322f">double</span> compression<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> TDigest<span style="color:#719e07">[]</span> ringBuffer<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#dc322f">int</span> currentBucket<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#dc322f">long</span> lastRotateTimestampMillis<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> <span style="color:#dc322f">long</span> durationBetweenRotatesMillis<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#268bd2">TimeWindowQuantile</span><span style="color:#719e07">(</span><span style="color:#dc322f">double</span> compression<span style="color:#719e07">,</span> <span style="color:#dc322f">int</span> bucketNum<span style="color:#719e07">,</span> <span style="color:#dc322f">int</span> timeWindowSeconds<span style="color:#719e07">)</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">this</span><span style="color:#719e07">.</span>compression <span style="color:#719e07">=</span> compression<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">this</span><span style="color:#719e07">.</span>ringBuffer <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> TDigest<span style="color:#719e07">[</span>bucketNum<span style="color:#719e07">];</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">for</span> <span style="color:#719e07">(</span><span style="color:#dc322f">int</span> i <span style="color:#719e07">=</span> 0<span style="color:#719e07">;</span> i <span style="color:#719e07">&lt;</span> bucketNum<span style="color:#719e07">;</span> i<span style="color:#719e07">++)</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">this</span><span style="color:#719e07">.</span>ringBuffer<span style="color:#719e07">[</span>i<span style="color:#719e07">]</span> <span style="color:#719e07">=</span> TDigest<span style="color:#719e07">.</span>createDigest<span style="color:#719e07">(</span>compression<span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">}</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">this</span><span style="color:#719e07">.</span>currentBucket <span style="color:#719e07">=</span> 0<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">this</span><span style="color:#719e07">.</span>lastRotateTimestampMillis <span style="color:#719e07">=</span> System<span style="color:#719e07">.</span>currentTimeMillis<span style="color:#719e07">();</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">this</span><span style="color:#719e07">.</span>durationBetweenRotatesMillis <span style="color:#719e07">=</span> TimeUnit<span style="color:#719e07">.</span>SECONDS<span style="color:#719e07">.</span>toMillis<span style="color:#719e07">(</span>timeWindowSeconds<span style="color:#719e07">)</span> <span style="color:#719e07">/</span> bucketNum<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">}</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#268bd2">synchronized</span> <span style="color:#dc322f">double</span> <span style="color:#268bd2">quantile</span><span style="color:#719e07">(</span><span style="color:#dc322f">double</span> q<span style="color:#719e07">)</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> TDigest currentBucket <span style="color:#719e07">=</span> rotate<span style="color:#719e07">();</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> currentBucket<span style="color:#719e07">.</span>quantile<span style="color:#719e07">(</span>q<span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">}</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#268bd2">synchronized</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">add</span><span style="color:#719e07">(</span><span style="color:#dc322f">double</span> value<span style="color:#719e07">)</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> rotate<span style="color:#719e07">();</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">for</span> <span style="color:#719e07">(</span>TDigest bucket <span style="color:#719e07">:</span> ringBuffer<span style="color:#719e07">)</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> bucket<span style="color:#719e07">.</span>add<span style="color:#719e07">(</span>value<span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">}</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">}</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> TDigest <span style="color:#268bd2">rotate</span><span style="color:#719e07">()</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">long</span> timeSinceLastRotateMillis <span style="color:#719e07">=</span> System<span style="color:#719e07">.</span>currentTimeMillis<span style="color:#719e07">()</span> <span style="color:#719e07">-</span> lastRotateTimestampMillis<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">while</span> <span style="color:#719e07">(</span>timeSinceLastRotateMillis <span style="color:#719e07">&gt;</span> durationBetweenRotatesMillis<span style="color:#719e07">)</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> ringBuffer<span style="color:#719e07">[</span>currentBucket<span style="color:#719e07">]</span> <span style="color:#719e07">=</span> TDigest<span style="color:#719e07">.</span>createDigest<span style="color:#719e07">(</span>compression<span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">if</span> <span style="color:#719e07">(++</span>currentBucket <span style="color:#719e07">&gt;=</span> ringBuffer<span style="color:#719e07">.</span>length<span style="color:#719e07">)</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> currentBucket <span style="color:#719e07">=</span> 0<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">}</span> |
| </span></span><span style="display:flex;"><span> timeSinceLastRotateMillis <span style="color:#719e07">-=</span> durationBetweenRotatesMillis<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> lastRotateTimestampMillis <span style="color:#719e07">+=</span> durationBetweenRotatesMillis<span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">}</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> ringBuffer<span style="color:#719e07">[</span>currentBucket<span style="color:#719e07">];</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">}</span> |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">}</span> |
| </span></span></code></pre></div><h3 id="指标推送">指标推送</h3> |
| <p>指标推送只有用户在设置了 <code>dubbo.metrics.protocol=prometheus</code> 参数后才开启,若只开启指标聚合,则默认不推送指标。</p> |
| <h4 id="prometheus-pull-service-discovery">Prometheus Pull Service Discovery</h4> |
| <p>目前 Dubbo Admin 内置了 prometheus http_sd service discovery 实例地址发现机制,Admin 默认会使用 <code>qos 端口</code>、 <code>/metrics</code> 作为这样 Admin 就能够将所有示例地址汇聚后以标准 http_sd 的方式同步给 Prometheus Server。</p> |
| <p>具体配置方式如下</p> |
| <p>其中,address、port、url 均是可选项,如不配置则 Admin 使用默认约定值。</p> |
| <blockquote> |
| <p>用户直接在Dubbo配置文件中配置Prometheus Pushgateway的地址即可,如&lt;dubbo:metrics protocol=&ldquo;prometheus&rdquo; mode=&ldquo;push&rdquo; address=&quot;${prometheus.pushgateway-url}&quot; interval=&ldquo;5&rdquo; /&gt;,其中interval代表推送间隔</p> |
| </blockquote></description></item><item><title>Overview: 链路追踪</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/observability/tracing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/observability/tracing/</guid><description> |
| <h2 id="概述">概述</h2> |
| <p>Dubbo 内置了全链路追踪能力,你可以通过引入 spring-boot-starter 或者相关依赖开启链路跟踪能力,通过将跟踪数据导出到一些主流实现如 Zipkin、Skywalking、Jaeger 等后端系统,可以实现全链路跟踪数据的分析与可视化展示。</p> |
| <p>Dubbo 目前借助 Micrometer Observation 完成 Tracing 的所有埋点工作,依赖 Micrometer 提供的各种 Bridge 适配,我们可以实现将 Tracing 导入各种后端系统,具体工作原理如下。</p> |
| <p><img src="https://dubbo.apache.org/imgs/docs3-v2/java-sdk/observability/micrometer-bridge.png" alt="micrometer-bridge"></p> |
| <h2 id="使用方式">使用方式</h2> |
| <p>以 Dubbo Spring Boot 应用为例,通过加入如下依赖即可开启链路追踪,并使用 zipkin exporter bridge 将链路追踪数据导入 Zipkin 后端系统。</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dependency&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;groupId&gt;</span>org.apache.dubbo<span style="color:#268bd2">&lt;/groupId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;artifactId&gt;</span>dubbo-spring-boot-tracing-otel-zipkin-starter<span style="color:#268bd2">&lt;/artifactId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;version&gt;</span>3.2.1-SNAPSHOT<span style="color:#268bd2">&lt;/version&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/dependency&gt;</span> |
| </span></span></code></pre></div><p>更多完整示例请参见:</p> |
| <ul> |
| <li><a href="https://dubbo.apache.org/zh-cn/overview/tasks/observability/tracing/zipkin/">使用 Zipkin 实现 Dubbo 全链路追踪</a></li> |
| <li><a href="https://dubbo.apache.org/zh-cn/overview/tasks/observability/tracing/skywalking/">使用 Skywalking 实现 Dubbo 全链路追踪</a></li> |
| </ul> |
| <h2 id="关联日志">关联日志</h2> |
| <p>Dubbo Tracing 还实现了与日志系统的自动关联,即将 tracing-id、span-id 等信息自动置入日志 MDC 上下文,你只需要设置日志输出格式中包含类似 <code>%X{traceId:-},%X{spanId:-}]</code>,即可实现业务日志与 tracing 系统的自动关联,具体可参见 <a href="https://github.com/apache/dubbo-samples/blob/master/4-governance/dubbo-samples-tracing/dubbo-samples-spring-boot-tracing-otel-otlp/provider/src/main/resources/application.yml">Tracing 日志上下文配置示例</a>。</p></description></item><item><title>Overview: 日志管理</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/observability/logging/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/observability/logging/</guid><description> |
| <p>在 Dubbo 框架内所有的日志输出都是通过 LoggerFactory 这个静态工厂类来获得 Logger 的对象实体,并且抽离了一个 LoggerAdapter 用于对接第三方日志框架,所以就有了JDKLoggerAdapter, Log4jLoggerAdapter, SLF4JLoggerAdapter等一些实现子类,分别对接了不同 Log 第三方实现。既然 Dubbo 能够支持这么多log实现,那么这些实现在 Dubbo 中优先级是在呢么样的呢?这里的优先级是指未配置指定的 logger 提供方的情况下,由 Dubbo 框架自己选择。优先级如下:</p> |
| <table> |
| <thead> |
| <tr> |
| <th>第三方日志框架</th> |
| <th>优先级</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td>Log4j</td> |
| <td>最高(默认就用这个)</td> |
| </tr> |
| <tr> |
| <td>SLF4J</td> |
| <td>次高(上面没有采用这个)</td> |
| </tr> |
| <tr> |
| <td>Common Logging(jcl就是common logging)</td> |
| <td>次低(Log4j和SLF4J在项目中均没有就用这个)</td> |
| </tr> |
| <tr> |
| <td>JDK log</td> |
| <td>最低(最后的选择)</td> |
| </tr> |
| </tbody> |
| </table> |
| <p>Dubbo 日志的调用方式,针对不同的日志打印系统,采用统一的 API 调用及输出,如:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#586e75">/** |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * ChannelListenerDispatcher |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> */</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">ChannelHandlerDispatcher</span> <span style="color:#268bd2">implements</span> ChannelHandler <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">static</span> <span style="color:#268bd2">final</span> ErrorTypeAwareLogger logger <span style="color:#719e07">=</span> LoggerFactory<span style="color:#719e07">.</span>getErrorTypeAwareLogger<span style="color:#719e07">(</span>ChannelHandlerDispatcher<span style="color:#719e07">.</span>class<span style="color:#719e07">);</span> |
| </span></span></code></pre></div><p>Dubbo 采用的日志输出方式是首先从 dubbo.application.logger 系统变量中获取属性值,来判断到底采用哪种日志输出方式,如果没设置则按照默认的加载顺序加载相应的日志输出类,直到成功加载:</p> |
| <p>顺序为:log4jLogger &gt; slf4jLogger &gt; JclLogger &gt; JdkLogger</p> |
| <p>LoggerFactory 在类加载过程中变量的初始化过程:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#586e75">// search common-used logging frameworks |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"></span><span style="color:#268bd2">static</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> String logger <span style="color:#719e07">=</span> System<span style="color:#719e07">.</span>getProperty<span style="color:#719e07">(</span><span style="color:#2aa198">&#34;dubbo.application.logger&#34;</span><span style="color:#719e07">,</span> <span style="color:#2aa198">&#34;&#34;</span><span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">switch</span> <span style="color:#719e07">(</span>logger<span style="color:#719e07">)</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">case</span> Slf4jLoggerAdapter<span style="color:#719e07">.</span>NAME<span style="color:#719e07">:</span> |
| </span></span><span style="display:flex;"><span> setLoggerAdapter<span style="color:#719e07">(</span><span style="color:#719e07">new</span> Slf4jLoggerAdapter<span style="color:#719e07">());</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">break</span><span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">case</span> JclLoggerAdapter<span style="color:#719e07">.</span>NAME<span style="color:#719e07">:</span> |
| </span></span><span style="display:flex;"><span> setLoggerAdapter<span style="color:#719e07">(</span><span style="color:#719e07">new</span> JclLoggerAdapter<span style="color:#719e07">());</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">break</span><span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">case</span> Log4jLoggerAdapter<span style="color:#719e07">.</span>NAME<span style="color:#719e07">:</span> |
| </span></span><span style="display:flex;"><span> setLoggerAdapter<span style="color:#719e07">(</span><span style="color:#719e07">new</span> Log4jLoggerAdapter<span style="color:#719e07">());</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">break</span><span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">case</span> JdkLoggerAdapter<span style="color:#719e07">.</span>NAME<span style="color:#719e07">:</span> |
| </span></span><span style="display:flex;"><span> setLoggerAdapter<span style="color:#719e07">(</span><span style="color:#719e07">new</span> JdkLoggerAdapter<span style="color:#719e07">());</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">break</span><span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">case</span> Log4j2LoggerAdapter<span style="color:#719e07">.</span>NAME<span style="color:#719e07">:</span> |
| </span></span><span style="display:flex;"><span> setLoggerAdapter<span style="color:#719e07">(</span><span style="color:#719e07">new</span> Log4j2LoggerAdapter<span style="color:#719e07">());</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">break</span><span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">default</span><span style="color:#719e07">:</span> |
| </span></span><span style="display:flex;"><span> List<span style="color:#719e07">&lt;</span>Class<span style="color:#719e07">&lt;?</span> <span style="color:#268bd2">extends</span> LoggerAdapter<span style="color:#719e07">&gt;&gt;</span> candidates <span style="color:#719e07">=</span> Arrays<span style="color:#719e07">.</span>asList<span style="color:#719e07">(</span> |
| </span></span><span style="display:flex;"><span> Log4jLoggerAdapter<span style="color:#719e07">.</span>class<span style="color:#719e07">,</span> |
| </span></span><span style="display:flex;"><span> Slf4jLoggerAdapter<span style="color:#719e07">.</span>class<span style="color:#719e07">,</span> |
| </span></span><span style="display:flex;"><span> Log4j2LoggerAdapter<span style="color:#719e07">.</span>class<span style="color:#719e07">,</span> |
| </span></span><span style="display:flex;"><span> JclLoggerAdapter<span style="color:#719e07">.</span>class<span style="color:#719e07">,</span> |
| </span></span><span style="display:flex;"><span> JdkLoggerAdapter<span style="color:#719e07">.</span>class |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">boolean</span> found <span style="color:#719e07">=</span> <span style="color:#cb4b16">false</span><span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// try to use the first available adapter |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"></span> <span style="color:#719e07">for</span> <span style="color:#719e07">(</span>Class<span style="color:#719e07">&lt;?</span> <span style="color:#268bd2">extends</span> LoggerAdapter<span style="color:#719e07">&gt;</span> clazz <span style="color:#719e07">:</span> candidates<span style="color:#719e07">)</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">try</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> LoggerAdapter loggerAdapter <span style="color:#719e07">=</span> clazz<span style="color:#719e07">.</span>getConstructor<span style="color:#719e07">().</span>newInstance<span style="color:#719e07">();</span> |
| </span></span><span style="display:flex;"><span> loggerAdapter<span style="color:#719e07">.</span>getLogger<span style="color:#719e07">(</span>LoggerFactory<span style="color:#719e07">.</span>class<span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">if</span> <span style="color:#719e07">(</span>loggerAdapter<span style="color:#719e07">.</span>isConfigured<span style="color:#719e07">())</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> setLoggerAdapter<span style="color:#719e07">(</span>loggerAdapter<span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span> found <span style="color:#719e07">=</span> <span style="color:#cb4b16">true</span><span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">break</span><span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">}</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">}</span> <span style="color:#719e07">catch</span> <span style="color:#719e07">(</span>Exception <span style="color:#719e07">|</span> LinkageError ignored<span style="color:#719e07">)</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// ignore |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"></span> <span style="color:#719e07">}</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">}</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">if</span> <span style="color:#719e07">(</span>found<span style="color:#719e07">)</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">break</span><span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">}</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> System<span style="color:#719e07">.</span>err<span style="color:#719e07">.</span>println<span style="color:#719e07">(</span><span style="color:#2aa198">&#34;Dubbo: Unable to find a proper configured logger to log out.&#34;</span><span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">for</span> <span style="color:#719e07">(</span>Class<span style="color:#719e07">&lt;?</span> <span style="color:#268bd2">extends</span> LoggerAdapter<span style="color:#719e07">&gt;</span> clazz <span style="color:#719e07">:</span> candidates<span style="color:#719e07">)</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">try</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> LoggerAdapter loggerAdapter <span style="color:#719e07">=</span> clazz<span style="color:#719e07">.</span>getConstructor<span style="color:#719e07">().</span>newInstance<span style="color:#719e07">();</span> |
| </span></span><span style="display:flex;"><span> loggerAdapter<span style="color:#719e07">.</span>getLogger<span style="color:#719e07">(</span>LoggerFactory<span style="color:#719e07">.</span>class<span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span> setLoggerAdapter<span style="color:#719e07">(</span>loggerAdapter<span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span> found <span style="color:#719e07">=</span> <span style="color:#cb4b16">true</span><span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">break</span><span style="color:#719e07">;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">}</span> <span style="color:#719e07">catch</span> <span style="color:#719e07">(</span>Throwable ignored<span style="color:#719e07">)</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// ignore |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"></span> <span style="color:#719e07">}</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">}</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">if</span> <span style="color:#719e07">(</span>found<span style="color:#719e07">)</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> System<span style="color:#719e07">.</span>err<span style="color:#719e07">.</span>println<span style="color:#719e07">(</span><span style="color:#2aa198">&#34;Dubbo: Using default logger: &#34;</span> <span style="color:#719e07">+</span> loggerAdapter<span style="color:#719e07">.</span>getClass<span style="color:#719e07">().</span>getName<span style="color:#719e07">()</span> <span style="color:#719e07">+</span> <span style="color:#2aa198">&#34;. &#34;</span> <span style="color:#719e07">+</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#2aa198">&#34;If you cannot see any log, please configure -Ddubbo.application.logger property to your preferred logging framework.&#34;</span><span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">}</span> <span style="color:#719e07">else</span> <span style="color:#719e07">{</span> |
| </span></span><span style="display:flex;"><span> System<span style="color:#719e07">.</span>err<span style="color:#719e07">.</span>println<span style="color:#719e07">(</span><span style="color:#2aa198">&#34;Dubbo: Unable to find any available logger adapter to log out. Dubbo logs will be ignored. &#34;</span> <span style="color:#719e07">+</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#2aa198">&#34;Please configure -Ddubbo.application.logger property and add corresponding logging library to classpath.&#34;</span><span style="color:#719e07">);</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">}</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">}</span> |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">}</span> |
| </span></span></code></pre></div><p>上面这段静态块是在LoggerFactory里面,说明只要LoggerFactory类一加载就会去选择对应的日志提供方。大家可能会发现对日志的提供方其实是可以通过配置来指定的,因为静态块一开始是从当前jvm环境中获取dubbo.application.logger,这个参数是同java -Ddubbo.application.logger=xxxx去指定的,如果是放在容器里面,就需要配置在容器启动的jvm参数里面。</p> |
| <h2 id="使用log4j来提供日志输出">使用Log4j来提供日志输出</h2> |
| <p>你不用做过多的处理就可以开启dubbo的日志,因为dubbo默认就是使用log4j。你唯一需要做的就是配置一个name是&quot;com.alibaba.dubbo&quot;的logger就可以了,然后关联到对应的appender。如下:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;appender</span> name=<span style="color:#2aa198">&#34;dubboAppender&#34;</span> class=<span style="color:#2aa198">&#34;org.apache.log4j.DailyRollingFileAppender&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;param</span> name=<span style="color:#2aa198">&#34;File&#34;</span> value=<span style="color:#2aa198">&#34;E:/dubbo.log&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;param</span> name=<span style="color:#2aa198">&#34;DatePattern&#34;</span> value=<span style="color:#2aa198">&#34;&#39;.&#39;yyyy-MM-dd&#39;.log&#39;&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;layout</span> class=<span style="color:#2aa198">&#34;org.apache.log4j.PatternLayout&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;param</span> name=<span style="color:#2aa198">&#34;ConversionPattern&#34;</span> |
| </span></span><span style="display:flex;"><span> value=<span style="color:#2aa198">&#34;[%d{MMdd HH:mm:ss SSS\} %-5p] [%t] %c{3\} - %m%n&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;/layout&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/appender&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;logger</span> name=<span style="color:#2aa198">&#34;com.alibaba.dubbo&#34;</span> additivity=<span style="color:#2aa198">&#34;false&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;priority</span> value =<span style="color:#2aa198">&#34;info&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;appender-ref</span> ref=<span style="color:#2aa198">&#34;dubboAppender&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/logger&gt;</span> |
| </span></span></code></pre></div><h2 id="使用logback来提供日志输出">使用logback来提供日志输出</h2> |
| <p>这种情况,默认是看不到dubbo的日志输出的,除非出现异常,被你当前系统的日志框架拦截住了。我这里就拿当前使用最多的日志框架logback来做示例。我们知道logback天生和slf4j进行了集成,所以要在项目里面使用logback,调用slf4j暴露的接口就可以。所以要把dubbo的日志输出切换到logback,也就变成了切换到slf4j了。</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;timestamp</span> key=<span style="color:#2aa198">&#34;byDate&#34;</span> datePattern=<span style="color:#2aa198">&#34;yyyyMMdd&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- dubbo log --&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;appender</span> name=<span style="color:#2aa198">&#34;dubboRolling&#34;</span> class=<span style="color:#2aa198">&#34;ch.qos.logback.core.rolling.RollingFileAppender&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;Encoding&gt;</span>UTF-8<span style="color:#268bd2">&lt;/Encoding&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;file&gt;</span>${LOG_HOME_DUBBO}/MTP-DUBBO.log<span style="color:#268bd2">&lt;/file&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;rollingPolicy</span> class=<span style="color:#2aa198">&#34;ch.qos.logback.core.rolling.TimeBasedRollingPolicy&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;fileNamePattern&gt;</span>${LOG_HOME_DUBBO}/DEMO-%d{yyyy-MM-dd}.%i-DUBBO.zip<span style="color:#268bd2">&lt;/fileNamePattern&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;maxHistory&gt;</span>30<span style="color:#268bd2">&lt;/maxHistory&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;TimeBasedFileNamingAndTriggeringPolicy</span> class=<span style="color:#2aa198">&#34;ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;MaxFileSize&gt;</span>100MB<span style="color:#268bd2">&lt;/MaxFileSize&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;/TimeBasedFileNamingAndTriggeringPolicy&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;/rollingPolicy&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;encoder&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;pattern&gt;</span>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n<span style="color:#268bd2">&lt;/pattern&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;immediateFlush&gt;</span>true<span style="color:#268bd2">&lt;/immediateFlush&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;/encoder&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;/appender&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;logger</span> name=<span style="color:#2aa198">&#34;com.alibaba.dubbo&#34;</span> level=<span style="color:#2aa198">&#34;DEBUG&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;appender-ref</span> ref=<span style="color:#2aa198">&#34;dubboRolling&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;/logger&gt;</span> |
| </span></span></code></pre></div><p>Dubbo 也可以将日志信息记录或者保存到文件中。</p> |
| <ol> |
| <li>使用<code>accesslog</code>输出到<code>log4j</code></li> |
| </ol> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:protocol</span> accesslog=<span style="color:#2aa198">&#34;true&#34;</span> name=<span style="color:#2aa198">&#34;dubbo&#34;</span> port=<span style="color:#2aa198">&#34;20880&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:protocol</span> accesslog=<span style="color:#2aa198">&#34;true&#34;</span> name=<span style="color:#2aa198">&#34;rmi&#34;</span> port=<span style="color:#2aa198">&#34;1099&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><ol start="2"> |
| <li>输出到文件</li> |
| </ol> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:protocol</span> accesslog=<span style="color:#2aa198">&#34;http://localhost/log.txt&#34;</span> name=<span style="color:#2aa198">&#34;dubbo&#34;</span> port=<span style="color:#2aa198">&#34;20880&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:protocol</span> accesslog=<span style="color:#2aa198">&#34;http://localhost/log2.txt&#34;</span> name=<span style="color:#2aa198">&#34;rmi&#34;</span> port=<span style="color:#2aa198">&#34;1099&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div></description></item></channel></rss> |