<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Apache SkyWalking – Nginx</title>
    <link>/tags/nginx/</link>
    <description>Recent content in Nginx on Apache SkyWalking</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Thu, 04 Jan 2024 00:00:00 +0000</lastBuildDate>
    
	  <atom:link href="/tags/nginx/feed.xml" rel="self" type="application/rss+xml" />
    
    
      
        
      
    
    
    <item>
      <title>Zh: SkyWalking 如何支持 ZIO 等 Scala Effect Runtime</title>
      <link>/zh/2024-01-04-skywalking-for-scala-effect-runtime/</link>
      <pubDate>Thu, 04 Jan 2024 00:00:00 +0000</pubDate>
      <guid>/zh/2024-01-04-skywalking-for-scala-effect-runtime/</guid>
      <description>
        
        
        &lt;h2 id=&#34;背景介绍&#34;&gt;背景介绍&lt;/h2&gt;
&lt;p&gt;在 Scala 中，纯函数式中主要使用 Fiber，而不是线程，诸如 &lt;a href=&#34;https://github.com/typelevel/cats-effect&#34;&gt;Cats-Effect&lt;/a&gt;、&lt;a href=&#34;https://github.com/zio/zio&#34;&gt;ZIO&lt;/a&gt; 等 Effect 框架。
您可以将 Fiber 视为轻量级线程，它是一种并发模型，由框架本身掌控控制权，从而消除了上下文切换的开销。
基于这些 Effect 框架开发的 HTTP、gRCP、GraphQL 库而开发的应用，我们一般称为 &lt;strong&gt;纯函数式应用程序&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;我们以 ZIO 为切入点， 演示 SkyWalking Scala 如何支持 Effect 生态。&lt;/p&gt;
&lt;h2 id=&#34;zio-trace&#34;&gt;ZIO Trace&lt;/h2&gt;
&lt;p&gt;首先，我们想要实现 Fiber 上下文传递，而不是监控 Fiber 本身。对于一个大型应用来说，可能存在成千上万个 Fiber，监控 Fiber 本身的意义不大。&lt;/p&gt;
&lt;p&gt;虽然 Fiber 的 Span 是在活跃时才会创建，但难免会有目前遗漏的场景，所以提供了一个配置 &lt;code&gt;plugin.ziov2.ignore_fiber_regexes&lt;/code&gt;。
它将使用正则去匹配 Fiber location，匹配上的 Fiber 将不会创建 Span。&lt;/p&gt;
&lt;p&gt;Fiber Span的信息如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;FiberSpan.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;下面是我们使用本 ZIO 插件，和一些官方插件（hikaricp、jdbc、pulsar）完成的 Trace：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;skywalking-scala-zio.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;分析&#34;&gt;分析&lt;/h2&gt;
&lt;p&gt;在 ZIO 中，Fiber可以有两种方式被调度，它们都是 &lt;code&gt;zio.Executor&lt;/code&gt; 的子类。当然您也可以使用自己的线程池，这样也需被 ZIO 包装，其实就类似下面的 &lt;code&gt;blockingExecutor&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;Executor&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;extends&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;ExecutorPlatformSpecific&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  self &lt;span style=&#34;color:#cf222e&#34;&gt;=&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#cf222e&#34;&gt;def&lt;/span&gt; submit&lt;span style=&#34;color:#0550ae&#34;&gt;(&lt;/span&gt;runnable&lt;span style=&#34;color:#cf222e&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;Runnable&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;)(&lt;/span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;implicit&lt;/span&gt; unsafe&lt;span style=&#34;color:#cf222e&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;Unsafe&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;Boolean&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一种是系统默认线程池 &lt;code&gt;defaultExecutor&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;private&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;zio&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;trait&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;RuntimePlatformSpecific&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#cf222e&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;val&lt;/span&gt; defaultExecutor&lt;span style=&#34;color:#cf222e&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;Executor&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#1f2328&#34;&gt;Executor&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;makeDefault&lt;span style=&#34;color:#0550ae&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;另一种是专用于阻塞 IO 的线程池 &lt;code&gt;blockingExecutor&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;private&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;zio&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;trait&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;RuntimePlatformSpecific&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#cf222e&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;val&lt;/span&gt; defaultBlockingExecutor&lt;span style=&#34;color:#cf222e&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;Executor&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#1f2328&#34;&gt;Blocking&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;blockingExecutor
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;默认线程池-defaultexecutor&#34;&gt;默认线程池 &lt;code&gt;defaultExecutor&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;对于 &lt;code&gt;defaultExecutor&lt;/code&gt;，其本身是很复杂的，但它就是一个 ZIO 的 Fiber 调度（执行）器：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57606a&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57606a&#34;&gt; * A `ZScheduler` is an `Executor` that is optimized for running ZIO
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57606a&#34;&gt; * applications. Inspired by &amp;#34;Making the Tokio Scheduler 10X Faster&amp;#34; by Carl
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57606a&#34;&gt; * Lerche. [[https://tokio.rs/blog/2019-10-scheduler]]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57606a&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;ZScheduler&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;extends&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;Executor&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;由于它们都是 &lt;code&gt;zio.Executor&lt;/code&gt; 的子类，我们只需要对其及其子类进行增强：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;ENHANCE_CLASS&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;LogicalMatchOperation&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;or&lt;span style=&#34;color:#0550ae&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#1f2328&#34;&gt;HierarchyMatch&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;byHierarchyMatch&lt;span style=&#34;color:#0550ae&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;zio.Executor&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#1f2328&#34;&gt;MultiClassNameMatch&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;byMultiClassMatch&lt;span style=&#34;color:#0550ae&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;zio.Executor&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;它们都是线程池，我们只需要在 &lt;code&gt;zio.Executor&lt;/code&gt; 的 &lt;code&gt;submit&lt;/code&gt; 方法上进行类似 &lt;code&gt;ThreadPoolExecutor&lt;/code&gt; 上下文捕获的操作，可以参考 &lt;a href=&#34;https://github.com/apache/skywalking-java/blob/main/apm-sniffer/bootstrap-plugins/jdk-threadpool-plugin/src/main/java/org/apache/skywalking/apm/plugin/ThreadPoolSubmitMethodInterceptor.java&#34;&gt;jdk-threadpool-plugin&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这里需要注意，因为 Fiber 也是一种 &lt;code&gt;Runnable&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;private&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;zio&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;trait&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;FiberRunnable&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;extends&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;Runnable&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#cf222e&#34;&gt;def&lt;/span&gt; location&lt;span style=&#34;color:#cf222e&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;Trace&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#cf222e&#34;&gt;def&lt;/span&gt; run&lt;span style=&#34;color:#0550ae&#34;&gt;(&lt;/span&gt;depth&lt;span style=&#34;color:#cf222e&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;Int&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;Unit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/bitlap/skywalking-scala/blob/master/plugins/zio-v2x-plugin/src/main/scala/org/bitlap/skywalking/apm/plugin/zio/v2x/define/ZioExecutorInstrumentation.scala&#34;&gt;zio-v2x-plugin&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;阻塞线程池-blockingexecutor&#34;&gt;阻塞线程池 &lt;code&gt;blockingExecutor&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;对于 &lt;code&gt;blockingExecutor&lt;/code&gt;，其实它只是对 Java 线程池进行了一个包装：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;object&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;Blocking&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#cf222e&#34;&gt;val&lt;/span&gt; blockingExecutor&lt;span style=&#34;color:#cf222e&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;zio.Executor&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    zio&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;Executor&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;fromThreadPoolExecutor &lt;span style=&#34;color:#0550ae&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#cf222e&#34;&gt;val&lt;/span&gt; corePoolSize  &lt;span style=&#34;color:#cf222e&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#cf222e&#34;&gt;val&lt;/span&gt; maxPoolSize   &lt;span style=&#34;color:#cf222e&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;Int&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;MaxValue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#cf222e&#34;&gt;val&lt;/span&gt; keepAliveTime &lt;span style=&#34;color:#cf222e&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;60000L&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#cf222e&#34;&gt;val&lt;/span&gt; timeUnit      &lt;span style=&#34;color:#cf222e&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;TimeUnit&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;MILLISECONDS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#cf222e&#34;&gt;val&lt;/span&gt; workQueue     &lt;span style=&#34;color:#cf222e&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;SynchronousQueue&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;Runnable&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;]()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#cf222e&#34;&gt;val&lt;/span&gt; threadFactory &lt;span style=&#34;color:#cf222e&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;NamedThreadFactory&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;zio-default-blocking&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#cf222e&#34;&gt;val&lt;/span&gt; threadPool &lt;span style=&#34;color:#cf222e&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;ThreadPoolExecutor&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        corePoolSize&lt;span style=&#34;color:#0550ae&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        maxPoolSize&lt;span style=&#34;color:#0550ae&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        keepAliveTime&lt;span style=&#34;color:#0550ae&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        timeUnit&lt;span style=&#34;color:#0550ae&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        workQueue&lt;span style=&#34;color:#0550ae&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        threadFactory
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0550ae&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      threadPool
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0550ae&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;由于其本身是对 &lt;code&gt;ThreadPoolExecutor&lt;/code&gt; 的封装，所以，当我们已经实现了 &lt;code&gt;zio.Executor &lt;/code&gt;的增强后，只需要使用官方 &lt;code&gt;jdk-threadpool-plugin&lt;/code&gt; 插件即可。
这里我们还想要对代码进行定制修改和复用，所以重新使用 Scala 实现了一个 &lt;a href=&#34;https://github.com/bitlap/skywalking-scala/blob/master/plugins/executors-plugin/src/main/scala/org/bitlap/skywalking/apm/plugin/executor/define/ThreadPoolExecutorInstrumentation.scala&#34;&gt;executors-plugin&lt;/a&gt; 插件。&lt;/p&gt;
&lt;h2 id=&#34;串连-fiber-上下文&#34;&gt;串连 Fiber 上下文&lt;/h2&gt;
&lt;p&gt;最后，上面谈到过，Fiber 也是一种 &lt;code&gt;Runnable&lt;/code&gt;，因此还需要对 &lt;code&gt;zio.internal.FiberRunnable&lt;/code&gt; 进行增强。大致分为两点，其实与 &lt;code&gt;jdk-threading-plugin&lt;/code&gt; 是一样的。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;每次创建 &lt;code&gt;zio.internal.FiberRunnable&lt;/code&gt; 实例时，都需要保存 &lt;strong&gt;现场&lt;/strong&gt;，即构造函数增强。&lt;/li&gt;
&lt;li&gt;每次运行时创建一个过渡的 Span，将当前线程上下文与之前保存在构造函数中的上下文进行关联。Fiber 可能被不同线程执行，所以这是必须的。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/bitlap/skywalking-scala/blob/master/plugins/zio-v2x-plugin/src/main/scala/org/bitlap/skywalking/apm/plugin/zio/v2x/define/ZioFiberRuntimeInstrumentation.scala&#34;&gt;zio-v2x-plugin&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;说明&#34;&gt;说明&lt;/h2&gt;
&lt;p&gt;当我们完成了对 ZIO Fiber 的上下文传播处理后，任意基于 ZIO 的应用层框架都可以按照普通的 Java 插件思路去开发。
我们只需要找到一个全局切入点，这个切入点应该是每个请求都会调用的方法，然后对这个方法进行增强。&lt;/p&gt;
&lt;p&gt;要想激活插件，只需要在 Release Notes 下载&lt;a href=&#34;https://github.com/bitlap/skywalking-scala/releases/tag/v0.2.0-beta1&#34;&gt;插件&lt;/a&gt;，放到您的 &lt;code&gt;skywalking-agent/plugins&lt;/code&gt; 目录，重新启动服务即可。&lt;/p&gt;
&lt;p&gt;如果您的项目使用 sbt assembly 打包，您可以参考这个 &lt;a href=&#34;https://github.com/bitlap/skywalking-scala/tree/master/scenarios&#34;&gt;示例&lt;/a&gt;。该项目使用了下列技术栈：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    libraryDependencies &lt;span style=&#34;color:#0550ae&#34;&gt;++=&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;Seq&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;io.d11&amp;#34;&lt;/span&gt;               &lt;span style=&#34;color:#0550ae&#34;&gt;%%&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;zhttp&amp;#34;&lt;/span&gt;                &lt;span style=&#34;color:#0550ae&#34;&gt;%&lt;/span&gt; zioHttp2Version&lt;span style=&#34;color:#0550ae&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;dev.zio&amp;#34;&lt;/span&gt;              &lt;span style=&#34;color:#0550ae&#34;&gt;%%&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;zio&amp;#34;&lt;/span&gt;                  &lt;span style=&#34;color:#0550ae&#34;&gt;%&lt;/span&gt; zioVersion&lt;span style=&#34;color:#0550ae&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;io.grpc&amp;#34;&lt;/span&gt;               &lt;span style=&#34;color:#0550ae&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;grpc-netty&amp;#34;&lt;/span&gt;           &lt;span style=&#34;color:#0550ae&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;1.50.1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;com.thesamet.scalapb&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;%%&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;scalapb-runtime-grpc&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;%&lt;/span&gt; scalapb&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;compiler&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;Version&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;scalapbVersion
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0550ae&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;++&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;Seq&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;dev.profunktor&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;%%&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;redis4cats-effects&amp;#34;&lt;/span&gt;  &lt;span style=&#34;color:#0550ae&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;1.3.0&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;dev.profunktor&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;%%&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;redis4cats-log4cats&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;1.3.0&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;dev.profunktor&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;%%&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;redis4cats-streams&amp;#34;&lt;/span&gt;  &lt;span style=&#34;color:#0550ae&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;1.3.0&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;org.typelevel&amp;#34;&lt;/span&gt;  &lt;span style=&#34;color:#0550ae&#34;&gt;%%&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;log4cats-slf4j&amp;#34;&lt;/span&gt;      &lt;span style=&#34;color:#0550ae&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;2.5.0&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;dev.zio&amp;#34;&lt;/span&gt;        &lt;span style=&#34;color:#0550ae&#34;&gt;%%&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;zio-interop-cats&amp;#34;&lt;/span&gt;    &lt;span style=&#34;color:#0550ae&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;23.0.03&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;ch.qos.logback&amp;#34;&lt;/span&gt;  &lt;span style=&#34;color:#0550ae&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;logback-classic&amp;#34;&lt;/span&gt;     &lt;span style=&#34;color:#0550ae&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;1.2.11&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;dev.zio&amp;#34;&lt;/span&gt;        &lt;span style=&#34;color:#0550ae&#34;&gt;%%&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;zio-cache&amp;#34;&lt;/span&gt;           &lt;span style=&#34;color:#0550ae&#34;&gt;%&lt;/span&gt; zioCacheVersion
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0550ae&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
      </description>
    </item>
    
    <item>
      <title>Zh: 使用 SkyWalking 监控 Nginx</title>
      <link>/zh/2023-12-23-monitoring-nginx-by-skywalking/</link>
      <pubDate>Sat, 23 Dec 2023 00:00:00 +0000</pubDate>
      <guid>/zh/2023-12-23-monitoring-nginx-by-skywalking/</guid>
      <description>
        
        
        &lt;h2 id=&#34;背景介绍&#34;&gt;背景介绍&lt;/h2&gt;
&lt;p&gt;在前面的 Blog &lt;a href=&#34;https://skywalking.apache.org/zh/2023-10-29-collect-and-analyse-nginx-accesslog-by-lal/&#34;&gt;使用 LAL 收集并分析 Nginx access log&lt;/a&gt; 中，我们以 Nginx access log 为切入点，
演示了 SkyWalking LAL 的日志分析能力。&lt;/p&gt;
&lt;p&gt;为了实现对 Nginx 更全面的监控能力，我们在 SkyWalking 9.7 中引入了 Nginx 监控面板，本文将演示该监控面板的使用，并介绍相关指标的含义。&lt;/p&gt;
&lt;h2 id=&#34;监控面板接入&#34;&gt;监控面板接入&lt;/h2&gt;
&lt;h3 id=&#34;metric-定义与采集&#34;&gt;Metric 定义与采集&lt;/h3&gt;
&lt;p&gt;由于使用了 &lt;a href=&#34;https://github.com/knyar/nginx-lua-prometheus&#34;&gt;nginx-lua-prometheus&lt;/a&gt; 来定义及暴露指标，
我们需要为 Nginx 安装 &lt;a href=&#34;https://github.com/openresty/lua-nginx-module&#34;&gt;lua_nginx_module&lt;/a&gt;， 或者直接使用&lt;a href=&#34;https://openresty.org&#34;&gt;OpenResty&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;下面的例子中，我们通过 nginx-lua-prometheus 定义了四个指标，并通过 ip:9145/metrics 暴露指标接口：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;histogram: nginx_http_latency，监控 http 延时&lt;/li&gt;
&lt;li&gt;gauge: nginx_http_connections，监控 http 连接数&lt;/li&gt;
&lt;li&gt;counter: nginx_http_size_bytes，监控 http 请求和响应大小&lt;/li&gt;
&lt;li&gt;counter: nginx_http_requests_total，监控 http 请求次数&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;http {
    log_format  main  &amp;#39;$remote_addr - $remote_user [$time_local] &amp;#34;$request&amp;#34; &amp;#39;
                      &amp;#39;$status $body_bytes_sent &amp;#34;$http_referer&amp;#34; &amp;#39;
                      &amp;#39;&amp;#34;$http_user_agent&amp;#34; &amp;#34;$http_x_forwarded_for&amp;#34;&amp;#39;;

    access_log  /var/log/nginx/access.log  main;

    lua_shared_dict prometheus_metrics 10M;
    # lua_package_path &amp;#34;/path/to/nginx-lua-prometheus/?.lua;;&amp;#34;;

    init_worker_by_lua_block {
      prometheus = require(&amp;#34;prometheus&amp;#34;).init(&amp;#34;prometheus_metrics&amp;#34;)

      metric_bytes = prometheus:counter(
        &amp;#34;nginx_http_size_bytes&amp;#34;, &amp;#34;Total size of HTTP&amp;#34;, {&amp;#34;type&amp;#34;, &amp;#34;route&amp;#34;})
      metric_requests = prometheus:counter(
        &amp;#34;nginx_http_requests_total&amp;#34;, &amp;#34;Number of HTTP requests&amp;#34;, {&amp;#34;status&amp;#34;, &amp;#34;route&amp;#34;})
      metric_latency = prometheus:histogram(
        &amp;#34;nginx_http_latency&amp;#34;, &amp;#34;HTTP request latency&amp;#34;, {&amp;#34;route&amp;#34;})
      metric_connections = prometheus:gauge(
        &amp;#34;nginx_http_connections&amp;#34;, &amp;#34;Number of HTTP connections&amp;#34;, {&amp;#34;state&amp;#34;})
    }

    server {
        listen 8080;

        location /test {
          default_type application/json;
          return 200  &amp;#39;{&amp;#34;code&amp;#34;: 200, &amp;#34;message&amp;#34;: &amp;#34;success&amp;#34;}&amp;#39;;

          log_by_lua_block {
            metric_bytes:inc(tonumber(ngx.var.request_length), {&amp;#34;request&amp;#34;, &amp;#34;/test/**&amp;#34;})
            metric_bytes:inc(tonumber(ngx.var.bytes_send), {&amp;#34;response&amp;#34;, &amp;#34;/test/**&amp;#34;})
            metric_requests:inc(1, {ngx.var.status, &amp;#34;/test/**&amp;#34;})
            metric_latency:observe(tonumber(ngx.var.request_time), {&amp;#34;/test/**&amp;#34;})
          }
        }
    }

    server {
      listen 9145;
      location /metrics {
        content_by_lua_block {
          metric_connections:set(ngx.var.connections_reading, {&amp;#34;reading&amp;#34;})
          metric_connections:set(ngx.var.connections_waiting, {&amp;#34;waiting&amp;#34;})
          metric_connections:set(ngx.var.connections_writing, {&amp;#34;writing&amp;#34;})
          prometheus:collect()
        }
      }
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;上面的例子中，我们暴露了 route 级别的指标，你也可以根据监控粒度的需要，选择暴露 host 指标：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;http {
  log_by_lua_block {
      metric_bytes:inc(tonumber(ngx.var.request_length), {&amp;#34;request&amp;#34;, ngx.var.host})
      metric_bytes:inc(tonumber(ngx.var.bytes_send), {&amp;#34;response&amp;#34;, ngx.var.host})
      metric_requests:inc(1, {ngx.var.status, ngx.var.host})
      metric_latency:observe(tonumber(ngx.var.request_time), {ngx.var.host})
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;或者 upstream 指标：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;upstream backend {
  server ip:port;
}

server {
  
  location /test_upstream {
  
    proxy_pass http://backend;
  
    log_by_lua_block {
      metric_bytes:inc(tonumber(ngx.var.request_length), {&amp;#34;request&amp;#34;, &amp;#34;upstream/backend&amp;#34;})
      metric_bytes:inc(tonumber(ngx.var.bytes_send), {&amp;#34;response&amp;#34;, &amp;#34;upstream/backend&amp;#34;})
      metric_requests:inc(1, {ngx.var.status, &amp;#34;upstream/backend&amp;#34;})
      metric_latency:observe(tonumber(ngx.var.request_time), {&amp;#34;upstream/backend&amp;#34;})
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;完成指标定义后，我们启动 nginx 和 opentelemetry-collector，将指标采集到 SkyWalking 后端进行分析和存储。&lt;/p&gt;
&lt;p&gt;请确保&lt;code&gt;job_name: &#39;nginx-monitoring&#39;&lt;/code&gt;，否则上报的数据将被 SkyWalking 忽略。如果你有多个 Nginx 实例，你可以通过&lt;code&gt;service&lt;/code&gt;及&lt;code&gt;service_instance_id&lt;/code&gt;这两个 label 进行区分：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;receivers:
  prometheus:
    config:
      scrape_configs:
        - job_name: &amp;#39;nginx-monitoring&amp;#39;
          scrape_interval: 5s
          metrics_path: &amp;#34;/metrics&amp;#34;
          static_configs:
            - targets: [&amp;#39;nginx:9145&amp;#39;]
              labels:
                service: nginx
                service_instance_id: nginx-instance
processors:
  batch:

exporters:
  otlp:
    endpoint: oap:11800
    tls:
      insecure: true
service:
  pipelines:
    metrics:
      receivers:
        - prometheus
      processors:
        - batch
      exporters:
        - otlp
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果一切顺利，你将在 skywalking-ui 的网关菜单下看到 nginx 上报的指标数据：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;nginx-metric.png&#34; alt=&#34;nginx-metric&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;access--error-log-采集&#34;&gt;Access &amp;amp; Error Log 采集&lt;/h3&gt;
&lt;p&gt;SkyWalking Nginx 监控提供了日志采集及错误日志统计功能，我们可以借助 &lt;a href=&#34;https://fluentbit.io/&#34;&gt;fluent-bit&lt;/a&gt; 采集并上报 access log、error log 给 SkyWalking 分析存储。&lt;/p&gt;
&lt;p&gt;下面 fluent-bit 配置定义了日志采集目录为&lt;code&gt;/var/log/nginx/&lt;/code&gt;，access 和 error log 经过 &lt;code&gt;rewrite_access_log&lt;/code&gt; 和 &lt;code&gt;rewrite_error_log&lt;/code&gt; 处理后会通过 oap 12800 端口进行上报：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[SERVICE]
    Flush          5
    Daemon         Off
    Log_Level      warn
[INPUT]
    Name           tail
    Tag            access
    Path           /var/log/nginx/access.log
[INPUT]
    Name           tail
    Tag            error
    Path           /var/log/nginx/error.log
[FILTER]
    Name           lua
    Match          access
    Script         fluent-bit-script.lua
    Call           rewrite_access_log
[FILTER]
    Name           lua
    Match          error
    Script         fluent-bit-script.lua
    Call           rewrite_error_log
[OUTPUT]
    Name            stdout
    Match           *
    Format          json
[OUTPUT]
    Name            http
    Match           *
    Host            oap
    Port            12800
    URI             /v3/logs
    Format          json
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在 fluent-bit-script.lua 中，我们通过 LOG_KIND 来区分 access log 和 error log。&lt;/p&gt;
&lt;p&gt;为了能够关联上文采集的 metric，请确保 service 和 serviceInstance 值与上文中指标采集定义一致。&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;function rewrite_access_log(tag, timestamp, record)
    local newRecord = {}
    newRecord[&amp;#34;layer&amp;#34;] = &amp;#34;NGINX&amp;#34;
    newRecord[&amp;#34;service&amp;#34;] = &amp;#34;nginx::nginx&amp;#34;
    newRecord[&amp;#34;serviceInstance&amp;#34;] = &amp;#34;nginx-instance&amp;#34;
    newRecord[&amp;#34;body&amp;#34;] = { text = { text = record.log } }
    newRecord[&amp;#34;tags&amp;#34;] = { data = {{ key = &amp;#34;LOG_KIND&amp;#34;, value = &amp;#34;NGINX_ACCESS_LOG&amp;#34;}}}
    return 1, timestamp, newRecord
end

function rewrite_error_log(tag, timestamp, record)
    local newRecord = {}
    newRecord[&amp;#34;layer&amp;#34;] = &amp;#34;NGINX&amp;#34;
    newRecord[&amp;#34;service&amp;#34;] = &amp;#34;nginx::nginx&amp;#34;
    newRecord[&amp;#34;serviceInstance&amp;#34;] = &amp;#34;nginx-instance&amp;#34;
    newRecord[&amp;#34;body&amp;#34;] = { text = { text = record.log } }
    newRecord[&amp;#34;tags&amp;#34;] = { data = {{ key = &amp;#34;LOG_KIND&amp;#34;, value = &amp;#34;NGINX_ERROR_LOG&amp;#34; }}}
    return 1, timestamp, newRecord
end
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;启动 fluent-it 后，我们便可以在监控面板的 Log tab 看到采集到的日志信息：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;nginx-log.png&#34; alt=&#34;nginx-log&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;面板指标含义&#34;&gt;面板指标含义&lt;/h2&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;面板名称&lt;/th&gt;
          &lt;th&gt;单位&lt;/th&gt;
          &lt;th&gt;指标含义&lt;/th&gt;
          &lt;th&gt;数据源&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;HTTP Request Trend&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
          &lt;td&gt;每秒钟平均请求数&lt;/td&gt;
          &lt;td&gt;nginx-lua-prometheus&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;HTTP Latency&lt;/td&gt;
          &lt;td&gt;ms&lt;/td&gt;
          &lt;td&gt;平均响应延时&lt;/td&gt;
          &lt;td&gt;nginx-lua-prometheus&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;HTTP Bandwidth&lt;/td&gt;
          &lt;td&gt;KB&lt;/td&gt;
          &lt;td&gt;请求响应流量&lt;/td&gt;
          &lt;td&gt;nginx-lua-prometheus&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;HTTP Connections&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
          &lt;td&gt;nginx http 连接数&lt;/td&gt;
          &lt;td&gt;nginx-lua-prometheus&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;HTTP Status Trend&lt;/td&gt;
          &lt;td&gt;%&lt;/td&gt;
          &lt;td&gt;每分钟 http 状态码统计&lt;/td&gt;
          &lt;td&gt;nginx-lua-prometheus&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;HTTP Status 4xx Percent&lt;/td&gt;
          &lt;td&gt;%&lt;/td&gt;
          &lt;td&gt;4xx状态码比例&lt;/td&gt;
          &lt;td&gt;nginx-lua-prometheus&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;HTTP Status 5xx Percent&lt;/td&gt;
          &lt;td&gt;%&lt;/td&gt;
          &lt;td&gt;5xx状态码比例&lt;/td&gt;
          &lt;td&gt;nginx-lua-prometheus&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Error Log Count&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
          &lt;td&gt;每分钟错误日志数统计&lt;/td&gt;
          &lt;td&gt;fluent-bit&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;参考文档&#34;&gt;参考文档&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/knyar/nginx-lua-prometheus&#34;&gt;nginx-lua-prometheus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.fluentbit.io/manual/pipeline/filters/lua&#34;&gt;fluent-bit-lua-filter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://skywalking.apache.org/docs/main/next/en/setup/backend/backend-apisix-monitoring&#34;&gt;skywalking-apisix-monitoring&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

      </description>
    </item>
    
    <item>
      <title>Zh: 使用 LAL 收集并分析 Nginx access log</title>
      <link>/zh/2023-10-29-collect-and-analyse-nginx-accesslog-by-lal/</link>
      <pubDate>Sun, 29 Oct 2023 00:00:00 +0000</pubDate>
      <guid>/zh/2023-10-29-collect-and-analyse-nginx-accesslog-by-lal/</guid>
      <description>
        
        
        &lt;h2 id=&#34;背景介绍&#34;&gt;背景介绍&lt;/h2&gt;
&lt;p&gt;Nginx access log 中包含了丰富的信息，例如：日志时间、状态码、响应时间、body 大小等。通过收集并分析 access log，我们可以实现对 Nginx 中接口状态的监控。&lt;/p&gt;
&lt;p&gt;在本案例中，将由 &lt;a href=&#34;https://fluentbit.io/&#34;&gt;fluent-bit&lt;/a&gt; 收集 access log，并通过 HTTP 将日志信息发送给 SkyWalking OAP Server 进行进一步的分析。&lt;/p&gt;
&lt;h2 id=&#34;环境准备&#34;&gt;环境准备&lt;/h2&gt;
&lt;p&gt;实验需要的 Nginx 及 Fluent-bit 相关配置文件都被上传到了&lt;a href=&#34;https://github.com/weixiang1862/nginx-fluent-bit&#34;&gt;Github&lt;/a&gt;，有需要的读者可以自行 git clone 并通过 docker compose 启动，本文中将介绍配置文件中几个关键点。&lt;/p&gt;
&lt;h3 id=&#34;nginx日志格式配置&#34;&gt;Nginx日志格式配置&lt;/h3&gt;
&lt;p&gt;LAL 目前支持 JSON、YAML 及 REGEX 日志解析，为了方便获取到日志中的指标字段，我们将 Nginx 的日志格式定义为 JSON.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;http {
    ...
    ...

    log_format  main  &amp;#39;{&amp;#34;remote_addr&amp;#34;: &amp;#34;$remote_addr&amp;#34;,&amp;#39;
            &amp;#39;&amp;#34;remote_user&amp;#34;: &amp;#34;$remote_user&amp;#34;,&amp;#39;
            &amp;#39;&amp;#34;request&amp;#34;: &amp;#34;$request&amp;#34;,&amp;#39;
            &amp;#39;&amp;#34;time&amp;#34;: &amp;#34;$time_iso8601&amp;#34;,&amp;#39;
            &amp;#39;&amp;#34;status&amp;#34;: &amp;#34;$status&amp;#34;,&amp;#39;
            &amp;#39;&amp;#34;request_time&amp;#34;:&amp;#34;$request_time&amp;#34;,&amp;#39;
            &amp;#39;&amp;#34;body_bytes_sent&amp;#34;: &amp;#34;$body_bytes_sent&amp;#34;,&amp;#39;
            &amp;#39;&amp;#34;http_referer&amp;#34;: &amp;#34;$http_referer&amp;#34;,&amp;#39;
            &amp;#39;&amp;#34;http_user_agent&amp;#34;: &amp;#34;$http_user_agent&amp;#34;,&amp;#39;
            &amp;#39;&amp;#34;http_x_forwarded_for&amp;#34;: &amp;#34;$http_x_forwarded_for&amp;#34;}&amp;#39;;

    access_log  /var/log/nginx/access.log  main;
    
    ...
    ...
}
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;fluent-bit-filter&#34;&gt;Fluent bit Filter&lt;/h3&gt;
&lt;p&gt;我们通过 Fluent bit 的 lua filter 进行日志格式的改写，将其调整为 SkyWalking 所需要的格式，record的各个字段含义如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;body：日志内容体&lt;/li&gt;
&lt;li&gt;service：服务名称&lt;/li&gt;
&lt;li&gt;serviceInstance：实例名称&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;function rewrite_body(tag, timestamp, record)
    local newRecord = {}
    newRecord[&amp;#34;body&amp;#34;] = { json = { json = record.log } }
    newRecord[&amp;#34;service&amp;#34;] = &amp;#34;nginx::nginx&amp;#34;
    newRecord[&amp;#34;serviceInstance&amp;#34;] = &amp;#34;localhost&amp;#34;
    return 1, timestamp, newRecord
end
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;oap-日志分析&#34;&gt;OAP 日志分析&lt;/h2&gt;
&lt;h3 id=&#34;lal定义&#34;&gt;LAL定义&lt;/h3&gt;
&lt;p&gt;在 filter 中，我们通过条件判断，只处理 &lt;code&gt;service=nginx::nginx&lt;/code&gt; 的服务，其他服务依旧走默认逻辑：&lt;/p&gt;
&lt;p&gt;第一步，使用 json 指令对日志进行解析，解析的结果会被存放到 parsed 字段中，通过 parsed 字段我们可以获取 json 日志中的字段信息。&lt;/p&gt;
&lt;p&gt;第二步，使用 timestamp 指令解析 parsed.time 并将其赋值给日志的 timestamp 字段，这里的 time 就是access log json 中的 time。&lt;/p&gt;
&lt;p&gt;第三步，使用 tag 指令给日志打上对应的标签，标签的值依然可以通过 parsed 字段获取。&lt;/p&gt;
&lt;p&gt;第四步，使用 metrics 指令从日志中提取出指标信息，我们共提取了四个指标：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nginx_log_count&lt;/code&gt;：Nginx 每次请求都会生成一条 access log，该指标可以帮助我们统计 Nginx 当前的请求数。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nginx_request_time&lt;/code&gt;：access log 中会记录请求时间，该指标可以帮助我们统计上游接口的响应时长。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nginx_body_bytes_sent&lt;/code&gt;：body 大小指标可以帮助我们了解网关上的流量情况。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nginx_status_code&lt;/code&gt;：状态码指标可以实现对状态码的监控，如果出现异常上涨可以结合 alarm 进行告警。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;rules&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;default&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;layer&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;GENERAL&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;dsl&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;|&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;      filter {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;        if (log.service == &amp;#34;nginx::nginx&amp;#34;) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;          json {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;            abortOnFailure true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;          }&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;          &lt;/span&gt;extractor {&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;            &lt;/span&gt;timestamp parsed.time as String, &amp;#34;yyyy-MM-dd&amp;#39;T&amp;#39;HH:mm:ssXXX&amp;#34;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;            &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;tag status&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;parsed.status&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;            &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;tag remote_addr&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;parsed.remote_addr&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;            &lt;/span&gt;metrics {&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;              &lt;/span&gt;timestamp log.timestamp as Long&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;              &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;labels service: log.service, instance&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;log.serviceInstance&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;              &lt;/span&gt;name &amp;#34;nginx_log_count&amp;#34;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;              &lt;/span&gt;value 1&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;            &lt;/span&gt;}&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;            &lt;/span&gt;metrics {&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;              &lt;/span&gt;timestamp log.timestamp as Long&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;              &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;labels service: log.service, instance&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;log.serviceInstance&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;              &lt;/span&gt;name &amp;#34;nginx_request_time&amp;#34;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;              &lt;/span&gt;value parsed.request_time as Double&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;            &lt;/span&gt;}&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;            &lt;/span&gt;metrics {&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;              &lt;/span&gt;timestamp log.timestamp as Long&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;              &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;labels service: log.service, instance&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;log.serviceInstance&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;              &lt;/span&gt;name &amp;#34;nginx_body_bytes_sent&amp;#34;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;              &lt;/span&gt;value parsed.body_bytes_sent as Long&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;            &lt;/span&gt;}&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;            &lt;/span&gt;metrics {&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;              &lt;/span&gt;timestamp log.timestamp as Long&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;              &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;labels service: log.service, instance: log.serviceInstance, status&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;parsed.status&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;              &lt;/span&gt;name &amp;#34;nginx_status_code&amp;#34;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;              &lt;/span&gt;value 1&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;            &lt;/span&gt;}&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;          &lt;/span&gt;}&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;        &lt;/span&gt;}&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;        &lt;/span&gt;sink {&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;        &lt;/span&gt;}&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;}&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;经过 LAL 处理后，我们已经可以在日志面板看到日志信息了，接下来我们将对 LAL 中提取的指标进行进一步分析：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;./nginx-log.jpg&#34; alt=&#34;nginx-log&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;mal定义&#34;&gt;MAL定义&lt;/h3&gt;
&lt;p&gt;在 MAL 中，我们可以对上一步 LAL 中提取的指标进行进一步的分析聚合，下面的例子里：&lt;/p&gt;
&lt;p&gt;nginx_log_count、nginx_request_time、nginx_status_code 使用 sum 聚合函数处理，并使用 SUM 方式 downsampling，&lt;/p&gt;
&lt;p&gt;nginx_request_time 使用 avg 聚合函数求平均值，默认使用 AVG 方式 downsampling。&lt;/p&gt;
&lt;p&gt;完成聚合分析后，SkyWalking Meter System 会完成对上述指标的持久化。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;expSuffix&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;service([&amp;#39;service&amp;#39;], Layer.GENERAL)&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;metricPrefix&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;nginx&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;metricsRules&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;cpm&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;exp&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;nginx_log_count.sum([&amp;#39;service&amp;#39;]).downsampling(SUM)&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;avg_request_time&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;exp&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;nginx_request_time.avg([&amp;#39;service&amp;#39;])&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;body_bytes_sent_count&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;exp&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;nginx_body_bytes_sent.sum([&amp;#39;service&amp;#39;]).downsampling(SUM)&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;status_code_count&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;exp&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;nginx_status_code.sum([&amp;#39;service&amp;#39;,&amp;#39;status&amp;#39;]).downsampling(SUM)&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后，我们便可以来到 SkyWalking UI 页面新建 Nginx 仪表板，使用刚刚 MAL 中定义的指标信息创建 Nginx Dashboard（也可以通过上文提到&lt;a href=&#34;https://github.com/weixiang1862/nginx-fluent-bit&#34;&gt;仓库&lt;/a&gt;中的 dashboard.json 直接导入测试）：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;./nginx-metric.jpg&#34; alt=&#34;nginx-metric&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;参考文档&#34;&gt;参考文档&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.fluentbit.io/manual/pipeline/filters/lua&#34;&gt;Fluent Bit lua Filter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://skywalking.apache.org/docs/main/next/en/concepts-and-designs/lal/&#34;&gt;Log Analysis Language&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://skywalking.apache.org/docs/main/next/en/concepts-and-designs/mal/&#34;&gt;Meter Analysis Language&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

      </description>
    </item>
    
  </channel>
</rss>
