ToB企服应用市场:ToB评测及商务社交产业平台

标题: Net8将Serilog日记推送ES,附视频 [打印本页]

作者: 反转基因福娃    时间: 2024-10-29 21:26
标题: Net8将Serilog日记推送ES,附视频
这是一个Serilog的实践Demo,包括了区别记录存放,AOP 日记记录,EF 执行记录,并且将日记推送到Elastic Search。

  说在前面的话

自从AI出来之后,学习的曲线瞬间变缓了,学习的路径也有了很大的变革。
与本人来说从前大多数都先知晓理论再找相关的框架官网或博客,然后去实践Demo,再加入到代码中,也就是理论-》实践-》应用-》技能。
而现在,可以在稍微知晓概念之后,直接找AI要Demo先跑起来,应用到代码中去,然后反向结合代码去问AI每一步实现的逻辑与理论,再消化成本身技能,也就是 概念-》应用-》理论知识-》技能。
故此次尝试差异的写文思绪,从拿到源代码的读者角度,开始思考与实践。
依照惯例,源代码在文末,必要自取~
情况准备


效果一览

实现要求

实现效果


Docker中启动 ES 和 SqlServer
再 F5 启动项目



全部的日记推送至Elastic Search
从Program 初见端倪

OK,信赖你现在已经把代码拉下来了,如果没有想生啃代码,不消跳过此节。
.net 8 与 .net 6 可以使用顶级语句,相对于.net 5 及从前的版本,去掉了Startup作为web的配置步伐,也就是上手各大项目的入口, 这里直接看Program 来探究Demo 怎样配置Web,来一窥端倪吧!
  1. using Autofac;
  2. using Autofac.Extensions.DependencyInjection;
  3. using Autofac.Extras.DynamicProxy;
  4. using Microsoft.EntityFrameworkCore;
  5. using SampleDemo.Yzh.Net.Logger;
  6. using SampleDemo.Yzh.Net.Repository;
  7. using SampleDemo.Yzh.Net.Service;
  8. using SampleDemo.Yzh.Net.Core;
  9. using Serilog;
  10. using ILogger = Serilog.ILogger;
  11. var builder = WebApplication.CreateBuilder(args);
  12. // Config
  13. builder.Services.AddSingleton(new AppSettings(builder.Configuration));
  14. // Serilog
  15. builder.Host.AddCustomLog();
  16. // EF
  17. builder.Services.AddDbContextPool<TestContext>
  18.     (o => o.UseSqlServer(builder.Configuration.GetConnectionString("NicoLocaldbStr"))
  19. #if DEBUG
  20.     .EnableSensitiveDataLogging()
  21. #endif
  22.     .UseLoggerFactory(LoggerFactory.Create(builder => builder.AddSerilog())
  23.     ));
  24. // Http Info
  25. builder.Services.AddHttpContextAccessor();
  26. // Auto Fac
  27. builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
  28. builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder =>
  29. {
  30.     // 注册AopDemo拦截器为单例模式
  31.     containerBuilder.RegisterType<AopDemo>().SingleInstance();
  32.     // InterceptedBy指定拦截器
  33.     containerBuilder.RegisterType<ValuesService>().As<IValuesService>().EnableInterfaceInterceptors().InterceptedBy(typeof(AopDemo));
  34.     // 或者在IValuesService 加标签 [Intercept(typeof(AopDemo))]
  35.     //containerBuilder.RegisterType<ValuesService>().As<IValuesService>().EnableInterfaceInterceptors();
  36.     //向 Autofac 容器注册 Log.Logger 这个已经存在的日志记录器实例 ,指定这个实例作为 ILogger 接口的实现 ,此ILogger为 Serilog的ILogger
  37.     //当应用程序中的组件通过依赖注入请求 ILogger 接口的实例时,它们会接收到 Log.Logger 这个单例对象
  38.     containerBuilder.RegisterInstance(Log.Logger).As<ILogger>();
  39. });
  40. builder.Services.AddControllers();
  41. var app = builder.Build();
  42. // Middleware
  43. app.UseMiddleware<ResponseLoggingMiddleware>(); //返回客户端响应的日志记录
  44. app.UseAuthorization();
  45. app.MapControllers();
  46. app.Run();
复制代码
这里我直接把Program.cs 51 行代码全部拉出来,由此来看大抵做了些什么。

  1. builder.Services.AddDbContextPool<TestContext>
  2.     (o => o.UseSqlServer(builder.Configuration.GetConnectionString("NicoLocaldbStr"))
  3. #if DEBUG
  4.     .EnableSensitiveDataLogging()
  5. #endif
  6.     .UseLoggerFactory(LoggerFactory.Create(builder => builder.AddSerilog())
  7.     ));
复制代码

再看Serilog拓展

从上文可知,使用了 AddCustomLog() 这样的一个扩展方法,注入了Serilog,OK! ,Ctrl + F12 进入一探究竟
  1.     public static class CustomLogger
  2.     {
  3.         public static IHostBuilder AddCustomLog(this IHostBuilder builder)
  4.         {
  5.             Log.Logger = new LoggerConfiguration()
  6.                 .ReadFrom.Configuration(AppSettings.Configuration)
  7.                 .Enrich.FromLogContext()
  8.                 // 输出到控制台
  9.                 .WriteToConsole()
  10.                 // 输出到文件
  11.                 .WriteToFile()
  12.                 // 输出到Es
  13.                 .WriteToElasticsearch()
  14.                 .CreateLogger();
  15.             builder.UseSerilog();
  16.             return builder;
  17.         }
  18.     }
复制代码

WriteToConsole与WriteToFile 也是拓展方法,那就继续Ctrl + F12 继续下去咯

  1. public static class LoggerConfigurationExtensions
  2. {
  3.     /// <summary>
  4.     /// 输出在控制台
  5.     /// </summary>
  6.     /// <param name="loggerConfiguration"></param>
  7.     /// <returns></returns>
  8.     public static LoggerConfiguration WriteToConsole(this LoggerConfiguration loggerConfiguration)
  9.     {
  10.         // 输出普通日志
  11.         loggerConfiguration = loggerConfiguration.WriteTo.Logger(lg =>
  12.             lg.FilterRemoveSqlLog().WriteTo.Console());
  13.         // 输出SQL
  14.         loggerConfiguration = loggerConfiguration.WriteTo.Logger(lg =>
  15.             lg.FilterSqlLog().WriteTo.Console());
  16.         return loggerConfiguration;
  17.     }
  18.     /// <summary>
  19.     /// 写入文件
  20.     /// </summary>
  21.     /// <param name="loggerConfiguration"></param>
  22.     /// <returns></returns>
  23.     public static LoggerConfiguration WriteToFile(this LoggerConfiguration loggerConfiguration)
  24.     {
  25.         // SQL语句写入
  26.         loggerConfiguration = loggerConfiguration.WriteTo.Logger(lg =>
  27.             lg.FilterSqlLog()
  28.                 .WriteTo.Async(s => s.File(LogContextStatic.Combine(LogContextStatic.EFSql, @"EFSql.txt"), rollingInterval: RollingInterval.Day,
  29.                     outputTemplate: LogContextStatic.FileMessageTemplate, retainedFileCountLimit: 31)));
  30.         // 非SQL写入
  31.         loggerConfiguration = loggerConfiguration.WriteTo.Logger(lg =>
  32.             lg.FilterRemoveSqlLog()
  33.                 .WriteTo.Async(s => s.File(LogContextStatic.Combine(LogContextStatic.AuditLogs, @"AuditLog.txt"), rollingInterval: RollingInterval.Hour,
  34.                 outputTemplate: LogContextStatic.FileMessageTemplate, retainedFileCountLimit: 31)));
  35.         return loggerConfiguration;
  36.     }
  37.     /// <summary>
  38.     /// 推送至 ES
  39.     /// </summary>
  40.     /// <param name="loggerConfiguration"></param>
  41.     /// <returns></returns>
  42.     public static LoggerConfiguration WriteToElasticsearch(this LoggerConfiguration loggerConfiguration)
  43.     {
  44.         var esUri = AppSettings.GetValue("ElasticConfiguration:Uri");
  45.         loggerConfiguration = loggerConfiguration.WriteTo.Elasticsearch(new ElasticsearchSinkOptions(
  46.                 new Uri(esUri))
  47.         {
  48.             AutoRegisterTemplate = true,
  49.             IndexFormat = "nico-api-log-{0:yyyy.MM.dd}",
  50.             ModifyConnectionSettings = con => con.ServerCertificateValidationCallback((sender, certificate, chain, sslPolicyErrors) => true)
  51.             .BasicAuthentication(
  52.                 AppSettings.GetValue("ElasticConfiguration:Es_UserName"),
  53.                 AppSettings.GetValue("ElasticConfiguration:Es_Pwd"))
  54.         });
  55.         return loggerConfiguration;
  56.     }
  57.     /// <summary>
  58.     /// 过滤出 SQL语句的日志
  59.     /// </summary>
  60.     /// <param name="lc"></param>
  61.     /// <returns></returns>
  62.     public static LoggerConfiguration FilterSqlLog(this LoggerConfiguration lc)
  63.     {
  64.         return lc.Filter.ByIncludingOnly(e =>
  65.         e.Properties.ContainsKey("SourceContext") &&
  66.         e.Properties["SourceContext"].ToString().Contains("Microsoft.EntityFrameworkCore.Database.Command"));
  67.     }
  68.     /// <summary>
  69.     /// 过滤非 SQL语句的日志
  70.     /// </summary>
  71.     /// <param name="lc"></param>
  72.     /// <returns></returns>
  73.     public static LoggerConfiguration FilterRemoveSqlLog(this LoggerConfiguration lc)
  74.     {
  75.         return lc.Filter.ByExcluding(e =>
  76.         e.Properties.ContainsKey("SourceContext") &&
  77.         e.Properties["SourceContext"].ToString().Contains("Microsoft.EntityFrameworkCore.Database.Command"));
  78.     }
  79. }
复制代码
注释非常细致,不再赘述,这里必要解释焦点的题目,怎样区别的SQL与非SQL的?
*日记上下文 (SourceContext):*Serilog 答应通过日记事件的属性来举行过滤。在这个例子中,使用了 SourceContext 属性,这是一个常用于标识日记来源的属性。对于由 Entity Framework Core 天生的日记,SourceContext 通常会包含值 “Microsoft.EntityFrameworkCore.Database.Command”,这表示日记条目是由 EF Core 在执行数据库命令时产生的。
*过滤器 (Filter.ByIncludingOnly):*这个方法答应配置日记系统仅包含符合特定条件的日记条目。在这里,条件是日记事件的属性中必须包含 SourceContext,并且其值包含 “Microsoft.EntityFrameworkCore.Database.Command”。这样,只有 EF Core 产生的数据库命令日记会被包括进来。
如果此节看懂了,下面实践绝对难不倒读者。
摆设ES

本人在摆设ES的时候遇到了很多坑,看到一些大佬的博客也是一笔带过,这里用Docker desktop 一步一步全部覆盖到位,跟着文章步骤走,绝对搞得定。
启动elasticsearch 、 kibana

起首先贴上 ES官方文档启动教程 https://www.elastic.co/guide/en/elasticsearch/reference/current/run-elasticsearch-locally.html
下载elasticsearch 、 kibana 镜像,本文截至24年7月30日,使用最新的ES版本8.14.3

docker创建网络

  1. docker network create elastic-net
复制代码

docker中启动ES,并且记着登录的暗码,加入集群的Token

  1. docker run --name es01 --net elastic -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -t elasticsearch:8.14.3
复制代码
启动之后,会在终端显示暗码,另有加入集群的Token,待会在启动kibana时要用,如果不小心关掉了,可以在docker desktop中,找到es的容器日记找到。

到这里ES启动完成,接下来启动Kibana
docker中启动kibana,加入集群

  1. docker run --name kib01 --net elastic -p 5601:5601 kibana:8.14.3
复制代码

http://0.0.0.0/5601 大概进不去(改了host文件的原因),用 http://localhost/5601即可

将token传入 ,静待摆设完成, 就进入了登录界面

账号默认为 elastic 暗码(小写) 则为一开始保存的 暗码,这里为 _*5O7P+5FKSV7nC_EDEE 记得改为你本身的 ,乐成登录之后就进入后台页面
ES后台创建数据集 (DataView)

创建 Data view , 此时必要重点注意 , Index pattern这里必要填对应索引的名称,匹配乐成才能在Discover中看到日记


至此 ES 搭建完成,现在要去将 Log 推送到 ES平台来

启动!!!

上文中已经将ES摆设好了,现在必要将项目跑起来,将日记推送到ES平台中去。
修改项目配置


数据库使用的是SQL Server , 必要修改为你本身的SQL 链接字符串即可。
  1.     "ConnectionStrings": {
  2.     // SQL Server
  3.     "NicoLocaldbStr": "Data Source=localhost;Initial Catalog=nicolocaldb;User ID=sa;Password=MyStrongPwd!2#;Trust Server Certificate=True"
  4.   }
复制代码
这里必要加张表
  1. -- SQL Server
  2. CREATE TABLE TestEFTable (
  3.     Id INT PRIMARY KEY IDENTITY(1,1),        -- Id 列为主键并设置为自增
  4.     Name NVARCHAR(255) NULL,                 -- Name 列,允许 NULL,使用 NVARCHAR 类型来支持 Unicode 字符
  5.     LastModifiedAt DATETIMEOFFSET NULL,      -- LastModifiedAt 列,允许 NULL,使用 DATETIMEOFFSET 类型
  6.     LastModifiedBy INT NOT NULL              -- LastModifiedBy 列,不允许 NULL
  7. );
复制代码
  1.   "ElasticConfiguration": {
  2.     "Uri": "https://localhost:9200",    // ES 地址
  3.     "Es_UserName": "elastic",           // 账号
  4.     "Es_Pwd": "_*5O7P+5FKSV7nC_EDEE"    // 密码
  5.   }
复制代码
ES 的配置同样修改为本身的配置。
原神启动!(bushi

F5启动! (以下是操作视频)
https://www.bilibili.com/video/BV1w3vUeWE4n/
总结

稍微总结一下,

源代码仓库 [GitHub] https://github.com/OrzCoCo-Y/LogSampleDemo
[Gitee] https://gitee.com/yi_zihao/LogSampleDemo
参考资料

【ChatGPT】
【严架的Maomi 框架】https://maomi.whuanle.cn 鉴戒了此中HTTP日记记录,代替了本身写中间件
【老八的哲学开源框架】https://github.com/anjoy8/Blog.Core 鉴戒了此中服务注册

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4