<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Serilog 日志庫簡單實踐(一):文件系統 Sinks(.net8)

      〇、前言

      前文已經介紹過什么是 Serilog,以及其核心特點,詳見:http://www.rzrgm.cn/hnzhengfy/p/19167414/Serilog_basic

      從本文開始,后續將對各種類型的 Sinks 進行簡單的實踐。

      本文將以文件系統相關的 Sinks 為主進行介紹,針對多個相關的動態庫,進行了簡介以及示例項目實現,供參考。

      一、文件系統 Sinks 用法

      1.1 Serilog.Sinks.File:最基礎的日志組件

      Serilog.Sinks.File 是 Serilog 社區維護的核心文件日志接收器,用于將日志事件寫入到一個或多個文本文件中。

      支持文本和 JSON 格式輸出,保留結構化數據,是 Serilog 生態中最基礎的文件日志組件。也支持按時間(如每天、每周)或大小滾動日志文件,可配置多進程共享日志文件,支持寫入緩沖以提高性能。

      如下是簡單實踐,可以簡單分為四步:

      1)創建 .NET 8 Web API 項目,并安裝 NuGet 包:

      dotnet add package Serilog.AspNetCore
      dotnet add package Serilog.Sinks.File
      // dotnet sdd package Serilog.Enrichers.Environment // 有需求要添加機器名時,需要添加此包
      // dotnet sdd package Swashbuckle.AspNetCore // 若需要使用 Swagger 時,需添加此包
      // 注意:使用 Serilog.AspNetCore 而不是基礎的 Serilog,
      //   因為它為 ASP.NET Core 提供了更好的集成(如自動記錄請求、依賴注入支持等)

      2)添加 appsettings.json 配置(非必要)。

      雖然當前示例項目中,主要在代碼中配置 Serilog,但也可以將部分設置放在 appsettings.json 中。

      例如:

      {
        "Serilog": { // 根節點
          "MinimumLevel": { // 定義了日志記錄的最低級別,只有等于或高于此級別的日志才會被記錄下來
            "Default": "Debug", // 全局默認的日志最低級別是 Debug
            "Override": { // 為特定命名空間或類庫重寫默認的日志級別
              "Microsoft": "Warning", // 所有來自 Microsoft 命名空間(例如框架內部代碼)的日志,只記錄 Warning 及以上級別(即 Warning, Error, Fatal)
              "Microsoft.AspNetCore": "Warning" // Microsoft.AspNetCore 相關組件(如 MVC、HTTP 請求管道等)也只記錄 Warning 及以上級別
            }
          }
        },
        "AllowedHosts": "*" // 用于控制應用響應哪些 HTTP 主機頭(Host header)的請求,"*" 表示允許所有主機訪問
          // 在開發環境下通常設為 "*",但在生產環境中建議明確指定受信任的主機以增強安全性
      }

      當全局默認的日志最低級別是 Debug 時,應用程序中所有代碼(除非特別覆蓋)產生的 Debug、Information、Warning、Error、Fatal 級別的日志都會被記錄。

      日志級別從低到高通常是:Verbose < Debug < Information < Warning < Error < Fatal。

      ASP.NET Core 框架本身會產生大量關于Microsoft、Microsoft.AspNetCore 兩個命名空間的 Information 和 Debug 級別的日志,如果不加限制,在生產環境中會非常冗長且影響性能。通過將其級別提高到 Warning,可以減少噪音日志,只關注真正重要的信息。

      3)修改 Program.cs(核心配置)

      using Microsoft.AspNetCore.Builder;
      using Serilog;
      using Serilog.Formatting.Json;
      
      var builder = WebApplication.CreateBuilder(args);
      
      Log.Logger = new LoggerConfiguration()
          .ReadFrom.Configuration(builder.Configuration) // 讀取 appsettings.json 中的 Serilog 配置
          .Enrich.FromLogContext()                      // 啟用上下文(如 BeginScope)
          .Enrich.WithMachineName()                    // 添加機器名 // 需要包:Serilog.Enrichers.Environment
          .Enrich.WithEnvironmentUserName()            // 添加用戶名
          .WriteTo.Console(new JsonFormatter())        // 控制臺也輸出 JSON(可選,便于開發)
          .WriteTo.File(
              path: "logs/api-.log",
              // formatter: new JsonFormatter(),           // 關鍵:使用 JSON 格式保留結構化數據
              formatter: new JsonFormatter(renderMessage: true), // renderMessage 加上此選項,日志中才會輸出"RenderedMessage"
              rollingInterval: RollingInterval.Day,     // 按天滾動
              fileSizeLimitBytes: 10_000_000,          // 單文件最大 10MB
              retainedFileCountLimit: 31,              // 最多保留 31 天
              rollOnFileSizeLimit: true,               // 達到大小限制時也滾動
              shared: true                             // 允許多個進程寫入(IIS/容器場景需要)
          )
          .CreateLogger();
      // 告訴 ASP.NET Core 使用 Serilog 作為日志提供者
      builder.Host.UseSerilog();
      
      // Add services to the container.
      builder.Services.AddControllers();
      builder.Services.AddEndpointsApiExplorer();
      builder.Services.AddSwaggerGen(); // 要使用 Swagger 需要添加包:Swashbuckle.AspNetCore
      
      var app = builder.Build();
      
      // 配置 HTTP 請求管道
      if (app.Environment.IsDevelopment())
      {
          app.UseSwagger();
          app.UseSwaggerUI();
      }
      
      // Configure the HTTP request pipeline.
      app.UseHttpsRedirection();
      app.UseAuthorization();
      app.MapControllers();
      
      // 在應用啟動時記錄一條結構化日志
      app.Lifetime.ApplicationStarted.Register(() =>
      {
          Log.Information("Application started. Environment: {Environment}, ContentRoot: {ContentRoot}",
              app.Environment.EnvironmentName,
              app.Environment.ContentRootPath);
      });
      // 在應用停止時記錄
      app.Lifetime.ApplicationStopping.Register(() =>
      {
          Log.Information("Application is stopping.");
      });
      
      app.Run();

      4)修改 WeatherForecastController.cs

      using Microsoft.AspNetCore.Mvc;
      
      namespace Test.WebAPI._8._0.Serilog.WriteToFile.Controllers
      {
          [ApiController]
          [Route("[controller]")]
          public class WeatherForecastController : ControllerBase
          {
              private static readonly string[] Summaries = new[]
              {
                  "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
              };
              private readonly ILogger<WeatherForecastController> _logger;
              public WeatherForecastController(ILogger<WeatherForecastController> logger)
              {
                  _logger = logger;
              }
              [HttpGet]
              public IEnumerable<WeatherForecast> Get()
              {
                  // 記錄結構化日志
                  _logger.LogInformation("Fetching weather forecasts for user {UserId} from IP {ClientIp}",
                      HttpContext.User.Identity?.Name ?? "Anonymous",
                      HttpContext.Connection.RemoteIpAddress?.ToString());
                  try
                  {
                      var rng = new Random();
                      var forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
                      {
                          Date = DateTime.Now.AddDays(index),
                          TemperatureC = rng.Next(-20, 55),
                          Summary = Summaries[rng.Next(Summaries.Length)]
                      }).ToArray();
                      // 記錄復雜對象(使用 @ 解構)
                      _logger.LogDebug("Generated {ForecastCount} forecasts: {@Forecasts}",
                          forecasts.Length, forecasts);
                      return forecasts;
                  }
                  catch (Exception ex)
                  {
                      // 記錄異常和上下文
                      _logger.LogError(ex, "An error occurred while generating weather forecasts for user {UserId}",
                          HttpContext.User.Identity?.Name ?? "Anonymous");
                      throw;
                  }
              }
          }
          public class WeatherForecast
          {
              public DateTime Date { get; set; }
              public int TemperatureC { get; set; }
              public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
              public string? Summary { get; set; }
          }
      }

      輸出結果:

      注:實際輸出為默認的 json 字符串,如下是格式化后便于查看。

      {
      	"Timestamp": "2025-10-23T23:30:44.9346095+08:00",
      	"Level": "Information",
      	"MessageTemplate": "Fetching weather forecasts for user {UserId} from IP {ClientIp}",
      	"RenderedMessage": "Fetching weather forecasts for user \"Anonymous\" from IP \"::1\"", // formatter: new JsonFormatter(renderMessage: true),配置效果
      	"TraceId": "8168e507fe989ade0dd4887075e3535e",
      	"SpanId": "9c78435a71c11ee6",
      	"Properties": {
      		"UserId": "Anonymous",
      		"ClientIp": "::1",
      		"SourceContext": "Test.WebAPI._8._0.Serilog.WriteToFile.Controllers.WeatherForecastController",
      		"ActionId": "15cb902a-b7c7-4b58-98e4-745dffec67e9",
      		"ActionName": "Test.WebAPI._8._0.Serilog.WriteToFile.Controllers.WeatherForecastController.Get (Test.WebAPI.8.0.Serilog.WriteToFile)",
      		"RequestId": "0HNGI94H06F88:00000001",
      		"RequestPath": "/weatherforecast",
      		"ConnectionId": "0HNGI94H06F88",
      		"MachineName": "WIN-J",
      		"EnvironmentUserName": "WIN-J\\Administrator"
      	}
      }

      1.2 Serilog.Sinks.Async:異步操作來避免主程阻塞

      Serilog.Sinks.Async 不是一個獨立的 Sink,而是一個異步包裝器,用于將任何其他同步的 Sink(如 Serilog.Sinks.File)包裝在異步操作中,減少日志記錄對主線程的阻塞(特別是 Web 請求線程)。

      在高并發場景下,如果日志直接寫入文件、數據庫或網絡服務,這些 I/O 操作是同步阻塞的。如果在每個請求中都記錄日志,會拖慢響應速度,甚至影響吞吐量。

      Serilog.Sinks.Async 將日志記錄工作委托給后臺線程,減少 I/O 瓶頸對應用性能的影響,特別適用于文件和數據庫等受 I/O 瓶頸影響的接收器。

      • 工作原理

      當程序調用 Log.Information() 時,日志事件被推入一個內部的異步隊列(默認大小是 1000 條)之后,立馬返回。一個后臺線程(或線程池任務)從隊列中取出日志,再交給被包裝的 Sink(如 File Sink)處理。主線程無需等待寫入完成,立即返回。

      另外需要注意,極端情況下可能丟失最后幾條日志(程序崩潰時),需要合理配置隊列大小和溢出策略。

      • 示例項目

      大概思路:分別生成兩個.net8.0 WebAPI 項目,一個使用同步,一個使用異步來實現將同樣的內容,以 json 字符串的格式寫入到文本文件中。啟動服務后,通過壓測工具(本文使用:wrk)觀察性能差異。

      下邊是實際操作的簡要步驟:

      1.2.1 創建兩個 .net 8.0 WebAPI 示例項目,然后添加幾個動態庫

      同步項目名稱:Test.WebAPI.8.0.Serilog.WriteToFile。異步實現項目:Test.WebAPI.Net8.Serilog.FileAsync。

      需要引用的動態庫:

      // 兩個項目都需要添加下邊三個包:
      dotnet add package Serilog.AspNetCore
      dotnet add package Serilog.Sinks.File
      dotnet add package Serilog.Formatting.Compact
      // 異步實現另外添加 Async 專用包:
      dotnet add package Serilog.Sinks.Async

      1.2.2 編輯 Program.cs

      同步項目實現:

      using Serilog;
      using Serilog.Events;
      using Serilog.Formatting.Compact;
      
      var builder = WebApplication.CreateBuilder(args);
      
      // 【配置 Serilog(同步)】
      builder.Host.UseSerilog((context, config) =>
      {
          config.WriteTo.File(
              path: "logs-sync/log-.txt",
              rollingInterval: RollingInterval.Day,
              retainedFileCountLimit: 30,
              // formatProvider: CultureInfo.InvariantCulture,
              // outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}",
              formatter: new RenderedCompactJsonFormatter(), // 配置使用json格式字符串輸出
              restrictedToMinimumLevel: LogEventLevel.Information
          );
      });
      
      var app = builder.Build();
      
      app.MapGet("/api/logSync", () =>
      {
          Log.Information("Fetching weather forecasts for user {UserId} from IP {ClientIp}",
                      "Anonymous",
                      "This is IP");
          return "Log recorded (synchronous)";
      });
      
      app.Run();

      異步項目實現:

      using Serilog;
      using Serilog.Events;
      using Serilog.Formatting.Compact;
      
      var builder = WebApplication.CreateBuilder(args);
      
      // 【配置 Serilog(異步)】
      builder.Host.UseSerilog((context, config) =>
      {
          config.WriteTo.Async(a => a.File(
              path: "logs-async/log-.txt",
              rollingInterval: RollingInterval.Day,
              retainedFileCountLimit: 30,
              //formatProvider: CultureInfo.InvariantCulture,
              //outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}",
              formatter: new RenderedCompactJsonFormatter(), // 配置使用json格式字符串輸出
              restrictedToMinimumLevel: LogEventLevel.Information
          ));
      });
      
      var app = builder.Build();
      
      app.MapGet("/api/logAsync", () =>
      {
          Log.Information("Fetching weather forecasts for user {UserId} from IP {ClientIp}",
                      "Anonymous",
                      "This is IP");
          return "Log recorded (asynchronous)";
      });
      
      app.Run();

      配置完成,同時啟動兩個項目,兩個服務地址例如:

      // 服務地址:
      http://localhost:5043/api/logSync
      http://localhost:5001/api/logAsync

      注:日志文件夾會在項目啟動時自動創建,無需手動配置或新增。

      1.2.3 測試與解析

      直接在 Windows 上通過 Docker 和 wrk 來進行的是兩種方式的性能差異。

      // 安裝和配置 Docker Desktop 步驟【略。。。】
      // 博主使用的鏡像源地址:"https://docker.xuanyuan.me",也可以使用阿里和騰訊的,哪個效率高用哪個
      // 拉取 wrk 包
      C:\Users\Administrator>docker pull williamyeh/wrk
      Using default tag: latest
      latest: Pulling from williamyeh/wrk
      4fe2ade4980c: Pull complete
      c4d7e348633d: Pull complete
      3e403d3ebdda: Pull complete
      bdb672ee55d9: Pull complete
      2bfb714176a4: Pull complete
      Digest: sha256:78adc0d9d51a99e6759e702a08d03eaece81c890ffcc9790ef9e5b199d54f091
      Status: Downloaded newer image for williamyeh/wrk:latest
      docker.io/williamyeh/wrk:latest
      // 異步記錄日志測試
      // 注意:host.docker.internal 是 Docker 宿主機的特殊 DNS 名稱,說明被測服務運行在宿主機上,而 wrk 在容器內發起請求
      C:\Users\Administrator>docker run -it --rm williamyeh/wrk -t12 -c100 -d10s http://host.docker.internal:5001/api/logAsync
      Running 10s test @ http://host.docker.internal:5001/api/logAsync
        12 threads and 100 connections
        Thread Stats   Avg      Stdev     Max   +/- Stdev
          Latency    15.59ms    5.85ms 103.93ms   93.31%
          Req/Sec   524.79    106.91   660.00     78.36%
        63040 requests in 10.01s, 10.82MB read
      Requests/sec:   6296.32
      Transfer/sec:      1.08MB
      // 同步記錄日志測試
      C:\Users\Administrator>docker run -it --rm williamyeh/wrk -t12 -c100 -d10s http://host.docker.internal:5043/api/logSync
      Running 10s test @ http://host.docker.internal:5043/api/logSync
        12 threads and 100 connections
        Thread Stats   Avg      Stdev     Max   +/- Stdev
          Latency    19.52ms    6.70ms  90.80ms   79.40%
          Req/Sec   413.05     43.31   656.00     85.56%
        49576 requests in 10.05s, 8.46MB read
      Requests/sec:   4930.52
      Transfer/sec:    862.05KB
      
      C:\Users\Administrator>
      // 關于 wrk -t12 -c100 -d10s
      // 同時開啟 12 個線程,每個線程與目標服務創建 100 個 TCP/HTTP keep-alive 連接,持續發起請求,持續 10 秒鐘
      // 相當于,在同一時間,有 1200 個連接在持續請求(一個請求完成,接著繼續發出下一個請求)目標服務

      下邊簡單分析下測試結果。

      指標 異步 (/logAsync) 同步 (/logSync) 對比
      總請求數 63,040 49,576 +27.1% ↑
      吞吐量 (Requests/sec) 6,296.32 4,930.52 +27.7% 提升
      傳輸速率 (Transfer/sec) 1.08 MB 862.05 KB +25.3% ↑
      平均延遲 (Latency Avg) 15.59ms 19.52ms 快 20%
      最大延遲 (Max Latency) 103.93ms 90.80ms 略高(可能因隊列堆積)
      延遲標準差 (Stdev) 5.85ms 6.70ms 更穩定
      每秒請求數波動 (Req/Sec Stdev) ±106.91 ±43.31 異步波動更大,但均值更高

      其中,異步操作的最大延遲稍高。可能原因:異步任務積壓在線程池或消息隊列中,在高峰期出現短暫排隊,導致個別請求的“真實完成時間”變長(但從 API 返回角度看仍是快的)。

      異步雖然吞吐高,但單位時間內請求處理數量波動更大,可能是由于線程調度、異步任務調度引入了不確定性。

      總結一下,就是異步顯著優于同步(+27% QPS,-20% 延遲)。

      1.3 Serilog.Sinks.RollingFile:已過時,無需單獨使用

      此動態庫主要功能是,配置日志文件如何按規則滾動,但現在已經在 Serilog.Sink.File 中進行了實現(詳見本文1.1),因此無需再使用此動態庫。

      這個變化是 Serilog 在 2.0 版本之后(特別是向 3.0 和 5.0 進化過程中)的一個重要的演變。

      但是,RollingFile 的功能并沒有消失,而是被整合并增強到了 Serilog.Sinks.File 包中。現在推薦的做法是:只安裝 Serilog.Sinks.File 這一個包,它就能滿足所有文件輸出需求,包括強大的滾動功能。

      Serilog.Sinks.File 的 File() 方法提供了以下關鍵參數來實現滾動:

      rollingInterval:這是最主要的滾動策略參數。它是一個 RollingInterval 枚舉,可選值包括:

      ??RollingInterval.Year:按年滾動。
      ??RollingInterval.Month:按月滾動。
      ??RollingInterval.Day:最常用,按天滾動。
      ??RollingInterval.Hour:按小時滾動。
      ??RollingInterval.Minute:按分鐘滾動(適用于極高日志量的場景)。
      ??RollingInterval.Infinite:不滾動,所有日志寫入單個文件。(注意:Infinite 在 Serilog 5.0 中以被移除,如需配置不滾動,可以通過略過此項配置來實現)。

      rollOnFileSizeLimit:一個布爾值。如果設置為 true,并且設置了 fileSizeLimitBytes,那么當日志文件達到指定大小時,也會觸發滾動,即使當前時間間隔(如一天)還未結束。這實現了“按大小或時間”任一條件滿足即滾動的邏輯。

      fileSizeLimitBytes:設置單個日志文件的最大字節數。達到此大小后,如果 rollOnFileSizeLimit 為 true,則會創建新文件。

      文件名中的 {Date} 占位符:當使用 rollingInterval 時,通常在文件路徑中包含 {Date}。Serilog 會自動用當前日期(格式為 yyyyMMdd)替換它,從而生成如 log-20251026.txt 的文件名。

      1.4 Serilog.Sinks.Map:根據日志屬性的值將日志時間路由到不同的 Sink

      Map 允許根據日志屬性的值將日志事件路由到不同的 Sink。例如,可以根據 UserId 將日志寫入不同的文件,非常適合需要按用戶或租戶隔離日志的場景

      因此,如果需要根據不同上下文(如用戶ID、請求ID、租戶ID等)將日志分發到不同的目標文件或處理邏輯,Map 是非常有用的;否則,一般不需要。

      需要注意的地方:

      ??性能開銷:Map 內部使用字典緩存子 logger,頻繁變化的鍵可能導致內存增長。
      ??過度設計風險:大多數場景下,統一結構化日志 + 集中式日志分析工具(如 Seq、ELK)更合適。
      ??Json 寫入本身不需要 Map:你完全可以用 WriteTo.File(..., formatter: new JsonFormatter()) 直接輸出 JSON 日志。

      典型應用場景就是,按 UserId 將審計日志寫入不同日志文件。

      1.4.1 創建測試項目并添加必要的包

      // 添加下邊三個包:
      dotnet add package Serilog.AspNetCore
      dotnet add package Serilog.Sinks.File
      dotnet add package Serilog.Sink.Map

      1.4.2 修改 Program.cs

      using Serilog;
      using Serilog.Context;
      using Serilog.Formatting.Compact;
      using Serilog.Formatting.Json;
      
      var builder = WebApplication.CreateBuilder(args);
      
      // 配置 Serilog
      Log.Logger = new LoggerConfiguration()
          .Enrich.FromLogContext()
          .MinimumLevel.Information()
          // 主日志:所有日志匯總到一個 JSON 文件
          .WriteTo.File(
              new JsonFormatter(),
              "logs/app-all-.json", 
              rollingInterval: RollingInterval.Day
          )
          // 特殊需求:按 UserId 分別記錄審計日志到獨立 JSON 文件
          .WriteTo.Map("UserId", "unknown", (id, wt) =>
          {
              wt.File(
                  path: $"logs/audit/user_{id}-.json",
                  formatter: new RenderedCompactJsonFormatter(), // 輸出為 JSON 格式
                  rollingInterval: RollingInterval.Day,
                  fileSizeLimitBytes: 10_000_000,
                  rollOnFileSizeLimit: true
              );
          })
          .CreateLogger();
      builder.Host.UseSerilog(); // 使用 Serilog 替代默認日志
      
      var app = builder.Build();
      // 模擬 API:記錄帶 UserId 的審計日志
      app.MapGet("/api/user/{id}/action", (int id, ILogger<Program> logger) =>
      {
          using (LogContext.PushProperty("UserId", id)) // 設置上下文屬性
          {
              Log.Information("User performed an action {id}", id);
              Log.Information("User viewed profile {TestParameters}", "測試字符串");
          }
          // 也可以直接記錄
          Log.ForContext("UserId", id).Information("Another action logged.");
          return Results.Ok(new { Message = "Action logged", UserId = id });
      });
      app.Run();

      1.4.3 測試結果驗證

      // 如下是兩個測試地址,分別是用戶 1001 和 1002
      http://localhost:5001/api/user/1001/action
      http://localhost:5001/api/user/1002/action

      注意,實際記錄的 json 格式日志是沒有格式化的,下面展示下格式化后的 json,僅為了方便查看。

      如下是 \logs\audit\user_1001-20251031.json 文件內容:

      {
          "@t": "2025-10-31T09:20:18.5714393Z",
          "@m": "User performed an action 1001",
          "@i": "0c7b7f7a",
          "@tr": "b93dc8db0938aac572cf3d92d437deaf",
          "@sp": "baa1c0bc7eb6880f",
          "id": 1001,
          "UserId": 1001,
          "RequestId": "0HNGOBQMLDQHE:00000001",
          "RequestPath": "/api/user/1001/action",
          "ConnectionId": "0HNGOBQMLDQHE"
      }
      {
          "@t": "2025-10-31T09:20:18.5783697Z",
          "@m": "User viewed profile \"測試字符串\"",
          "@i": "acc2ba35",
          "@tr": "b93dc8db0938aac572cf3d92d437deaf",
          "@sp": "baa1c0bc7eb6880f",
          "TestParameters": "測試字符串",
          "UserId": 1001,
          "RequestId": "0HNGOBQMLDQHE:00000001",
          "RequestPath": "/api/user/1001/action",
          "ConnectionId": "0HNGOBQMLDQHE"
      }
      {
          "@t": "2025-10-31T09:20:18.5794363Z",
          "@m": "Another action logged.",
          "@i": "58648cce",
          "@tr": "b93dc8db0938aac572cf3d92d437deaf",
          "@sp": "baa1c0bc7eb6880f",
          "UserId": 1001,
          "RequestId": "0HNGOBQMLDQHE:00000001",
          "RequestPath": "/api/user/1001/action",
          "ConnectionId": "0HNGOBQMLDQHE"
      }

      另外兩個日志文件內容就略過了:

      \logs\app-all-20251031.json

      \logs\audit\user_1002-20251031.json

      輸出日志內容為 json 格式,然后就可以用 ELK / Seq / Loki 等工具做結構化解析和查詢,這才是現代日志實踐。

      以上,就是對文件系統 Sink 的全部實踐記錄了,后續還有其他類型的 Sink 持續挖掘中。

      posted @ 2025-10-31 21:18  橙子家  閱讀(202)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 成人伊人青草久久综合网| 日本五十路熟女一区二区| 亚洲 制服 丝袜 无码| 久久婷婷五月综合97色直播| A毛片终身免费观看网站| 国产明星精品无码AV换脸| 国产精品自拍视频免费看| 久久精品女人的天堂av| 成人午夜视频在线| 国产精品久久久久久av| 精品亚洲国产成人性色av| 国产亚洲色视频在线| 国产综合久久99久久| 日韩精品人妻黄色一级片| 欧美视频网站www色| 黑人异族巨大巨大巨粗| 一本久道中文无码字幕av| 成人亚洲国产精品一区不卡 | av午夜福利亚洲精品福利| 性一交一乱一伦| 青青草无码免费一二三区| 日韩乱码人妻无码系列中文字幕| 亚洲成av人片无码迅雷下载| 中文国产不卡一区二区| 欧美一区二区三区久久综合| 成av人片一区二区久久| 日韩丝袜人妻中文字幕| 精品麻豆国产色欲色欲色欲WWW| 久久丫精品久久丫| av无码小缝喷白浆在线观看| 亚洲最大成人美女色av| 強壮公弄得我次次高潮A片| 国产一区在线播放av| 久久精品熟女亚洲av麻| 亚洲日韩一区二区| 国产成人无码免费视频麻豆| 彩票| 亚洲精品成人福利网站| 国产免费午夜福利在线播放| 国产精品激情av在线播放| 无码专区视频精品老司机|