.net core 使用阿里雲分佈式日誌

前言

好久沒有出來誇白了,今天教大家簡單的使用阿里雲分佈式日誌,來存儲日誌,沒有阿里雲賬號的,可以免費註冊一個

blockchain

開通阿里雲分佈式日誌(有一定的免費額度,個人測試學習完全沒問題的,香)

阿里雲日誌地址://sls.console.aliyun.com/lognext/profile

  1. 先開通阿里雲日誌,這個比較簡單授權就可以了

  2. 選擇接入數據,我們這裡選 .NET

    blockchain

  3. 選擇項目名稱,沒有項目的可以去創建一個,項目名稱後面會用到,如果你有購買阿里雲ECS,項目區域最好選擇跟ECS同一個區域(每個區域的地址不一樣,同一個區域可以選擇內網通訊,速度更快),如果沒有,就隨便選個區域,我這裡選擇的是杭州

    blockchain

  4. 選擇日誌庫,沒有就創建一個

    blockchain

  5. 數據源配置,這個先不用管,後面有教程

  6. 設置分析配置,例如我這裡設置了兩個,可以根據業務需求來,沒有特殊要求不用設置

    blockchain

  7. 開通完成,可以正常看到儀盤表

    blockchain

  8. 設置密鑰

    blockchain

通過SDK 寫入日誌

    LogServiceClientBuilders.HttpBuilder
    .Endpoint("<endpoint>", "<projectName>")
    .Credential("<accessKeyId>", "<accessKey>")
    .Build();
  • 阿里雲提供的依賴注入代碼(autofac),很遺憾按照這個方式,並沒有獲取到對象
using Aliyun.Api.LogService;
using Autofac;

namespace Examples.DependencyInjection
{
    public static class AutofacExample
    {
        public static void Register(ContainerBuilder containerBuilder)
        {
            containerBuilder
                .Register(context => LogServiceClientBuilders.HttpBuilder
                    // 服務入口<endpoint>及項目名<projectName>
                    .Endpoint("<endpoint>", "<projectName>")
                    // 訪問密鑰信息
                    .Credential("<accessKeyId>", "<accessKey>")
                    .Build())
                // `ILogServiceClient`所有成員是線程安全的,建議使用Singleton模式。
                .SingleInstance();
        }
    }
}
  • 中間個有小插曲,由於公司使用阿里雲日誌比較早,也非常穩定,替換成我申請的阿里雲日誌的配置,發送日誌一直報錯,找了半天沒找到原因,提了工單,原來阿里雲使用了新的SDK
    blockchain
    blockchain

blockchain

重新封裝阿里雲日誌SDK(Aliyun.Log.Core) //github.com/wmowm/Aliyun.Log.Core

  • 問了下群友,剛好有大佬重寫過向阿里雲提交日誌這塊,一番py交易,代碼塊到手,主要是數據組裝,加密,發送,發送部分的代碼基於http的protobuf服務實現,這裡直接從阿里雲開源的SDK里拷貝過來,開始重新封裝,主要實現以下功能
  1. 實現 .net core DI
  2. 加入隊列,讓日誌先入列,再提交到阿里雲,提高系統吞吐量
  3. 對日誌模型進行封裝,滿足基礎業務需求

代碼如下

  1. 添加ServiceCollection 拓展,定義一個阿里雲日誌的配置信息委託,然後將需要注入的服務註冊進去即可
  public static AliyunLogBuilder AddAliyunLog(this IServiceCollection services, Action<AliyunSLSOptions> setupAction)
  {
      if (setupAction == null)
      {
          throw new ArgumentNullException(nameof(setupAction));
      }
      //var options = new AliyunSLSOptions();
      //setupAction(options);
      services.Configure(setupAction);
      services.AddHttpClient();
      services.AddSingleton<AliyunSLSClient>();
      services.AddSingleton<AliyunLogClient>();
      services.AddHostedService<HostedService>();

      return new AliyunLogBuilder(services);
  }
  1. 加入隊列比較簡單,定義一個隊列,使用HostedService 消費隊列
  /// <summary>
  /// 寫日誌
  /// </summary>
  /// <param name="log"></param>
  /// <returns></returns>
  public async Task Log(LogModel log)
  {
      AliyunLogBuilder.logQueue.Enqueue(log);
  }
  /// <summary>
  /// 消費隊列
  /// </summary>
  Task.Run(async () =>
  {
      using (var serviceScope = _provider.GetService<IServiceScopeFactory>().CreateScope())
      {
          var _options = serviceScope.ServiceProvider.GetRequiredService<IOptions<AliyunSLSOptions>>();
          var _client = serviceScope.ServiceProvider.GetRequiredService<AliyunSLSClient>();
          while (true)
          {
              try
              {
                  if (AliyunLogBuilder.logQueue.Count>0)
                  {
                      var log = AliyunLogBuilder.logQueue.Dequeue();
                      var logInfo = new LogInfo
                      {
                          Contents =
                      {
                          {"Topic", log.Topic.ToString()},
                          {"OrderNo", log.OrderNo},
                          {"ClassName", log.ClassName},
                          { "Desc",log.Desc},
                          { "Html",log.Html},
                          { "PostDate",log.PostDate},
                      },
                          Time = DateTime.Parse(log.PostDate)
                      };
                      List<LogInfo> list = new List<LogInfo>() { logInfo };
                      var logGroupInfo = new LogGroupInfo
                      {
                          Topic = log.Topic.ToString(),
                          Source = "localhost",
                          Logs = list
                      };
                      await _client.PostLogs(new PostLogsRequest(_options.Value.LogStoreName, logGroupInfo));
                  }
                  else
                  {
                      await Task.Delay(1000);
                  }

              }
              catch (Exception ex)
              {
                  await Task.Delay(1000);
              }
          }
      }
  });
  1. 定義日誌模型,可以根據業務情況拓展
  public class LogModel
  {
      /// <summary>
      /// 所在類
      /// </summary>
      public string ClassName { get; set; }


      /// <summary>
      /// 訂單號
      /// </summary>
      public string OrderNo { get; set; }


      /// <summary>
      /// 提交時間
      /// </summary>
      public string PostDate { get; set; }


      /// <summary>
      /// 描述
      /// </summary>
      public string Desc { get; set; }


      /// <summary>
      /// 長字段描述
      /// </summary>
      public string Html { get; set; }

      /// <summary>
      /// 日誌主題
      /// </summary>
      public string Topic { get; set; } = "3";

  }

使用Aliyun.Log.Core

  1. 獲取Aliyun.Log.Core包

方案A. install-package Aliyun.Log.Core

方案B. nuget包管理工具搜索 Aliyun.Log.Core

  1. 添加中間件
services.AddAliyunLog(m =>
    {
        m.AccessKey = sls.GetValue<string>("AccessKey");
        m.AccessKeyId = sls.GetValue<string>("AccessKeyId");
        m.Endpoint = sls.GetValue<string>("Host");
        m.Project = sls.GetValue<string>("Project");
        m.LogStoreName = sls.GetValue<string>("LogstoreName");
    });
  1. 寫入日誌
//獲取對象
private readonly IOptions<SlsOptions> _options;
private readonly AliyunLogClient _aliyunLogClient;
public HomeController(IOptions<SlsOptions> options, AliyunLogClient aliyunLogClient)
{
    _options = options;
    _aliyunLogClient = aliyunLogClient;
}

[HttpGet("/api/sendlog")]
public async Task<JsonResult> SendLog(string topic="1")
{
    //日誌模型
    LogModel logModel = new LogModel()
    {
        ClassName = "Aliyun.log",
        Desc = "6666666666xxxxxx",
        Html = "99999999999xxxxx",
        Topic = topic,
        OrderNo = Guid.NewGuid().ToString("N"),
        PostDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
    };
    await _aliyunLogClient.Log(logModel);
    return Json("0");
}

簡單的查詢日誌

blockchain