NetCore微服务实战体系:日志管理
一. 起始
进入NetCore时代,日志的使用有了很大的变化,因为跨平台以及虚拟化技术的使用,日志不能够再像Framework的方式直接记录在文本,文本其实也可以,但是日志的管理以及查看都不太方便。Linux都是指令化,对于开发来说并不友好。
后来Exceptionless进入了视线,选择这个组件的原因很简单,可视化、数据统计、实时性以及对于.net开发人员相当友好。在当前网络上,有很多关于Exceptionless的使用文档,但是个人觉得并不友好,在使用上并不方便。
在微软体系中,Microsoft.Extesions.Logging是官方日志框架,它允许我们自己去实现ILoggerProvider / ILogging,那么根据这两者得特性,由此开发了组件 Overt.Core.Logging
二. 组件Overt.Core.Logging
https://github.com/overtly/logging
三. 简单介绍使用
1. Nuget包引用
- Nuget版本:V 1.0.4.1
- 框架支持: NetStandard 2.0
Install-Package Overt.Core.Logging -Version 1.0.4.1
2. 配置信息
- NetCore配置案例 appsettings.json
{
"Exceptionless": {
"ServerUrl": "http://exless.g.lan", // 私有化域名(Exceptionless私有化的文档网上很多)
"ApiKey": "ugGFmeeriaj1BG12itWWURfiJjwqiyi2o71ll4mm", // 项目Key 如何创建网上文档也很多
"Tags": "Local" // 日志所属项目环境
}
}
3. 具体使用
(1)服务注入
- Web服务使用
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{// Logging
app.AddExlessLogging(); }
- IHost 普通服务使用
static void Main(string[] args)
{
var host = new HostBuilder()
.UseConsoleLifetime() //使用控制台生命周期
.ConfigureAppConfiguration((context, configuration) =>
{
configuration
.AddJsonFile("appsettings.json", optional: true)
.AddEnvironmentVariables();
})
.ConfigureLogging(logger =>
{ })
.ConfigureServices(ConfigureServices)
.Build(); host.Services.AddExlessLogging();
ThreadPool.SetMinThreads(100, 100); AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
{
var logFactory = host.Services.GetService<ILoggerFactory>();
var logger = logFactory.CreateLogger<Program>();
logger.LogError(e.ExceptionObject as Exception, $"UnhandledException");
}; host.Run();
}
(2)日志使用
using Microsoft.Extensions.Logging; private readonly ILogger _logger; public Test(ILogger<Test> logger)
{
_logger = logger;
} _logger.LogInformation("你好");
4. 源码详解
(1)实现ILogger
using Exceptionless;
using Microsoft.Extensions.Logging;
using System; namespace Overt.Core.Logging
{
/// <summary>
/// Logger实现
/// </summary>
public class ExlessLogger : ILogger
{
private readonly string _categoryName;
public ExlessLogger(string categoryName)
{
_categoryName = categoryName;
} /// <summary>
///
/// </summary>
/// <typeparam name="TState"></typeparam>
/// <param name="state"></param>
/// <returns></returns>
public IDisposable BeginScope<TState>(TState state)
{
return new NoopDisposable();
} /// <summary>
/// 是否可用
/// </summary>
/// <param name="logLevel"></param>
/// <returns></returns>
public bool IsEnabled(LogLevel logLevel)
{
return true;
} /// <summary>
/// 记录日志
/// </summary>
/// <typeparam name="TState"></typeparam>
/// <param name="logLevel"></param>
/// <param name="eventId"></param>
/// <param name="state"></param>
/// <param name="exception"></param>
/// <param name="formatter"></param>
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
try
{
var message = formatter(state, exception);
var source = $"{_categoryName}";
var exlessLogLevel = Exceptionless.Logging.LogLevel.Trace;
switch (logLevel)
{
case LogLevel.Trace:
exlessLogLevel = Exceptionless.Logging.LogLevel.Trace;
break;
case LogLevel.Information:
exlessLogLevel = Exceptionless.Logging.LogLevel.Info;
break;
case LogLevel.Warning:
exlessLogLevel = Exceptionless.Logging.LogLevel.Warn;
break;
case LogLevel.Error:
exlessLogLevel = Exceptionless.Logging.LogLevel.Error;
break;
case LogLevel.Critical:
exlessLogLevel = Exceptionless.Logging.LogLevel.Fatal;
break;
default:
exlessLogLevel = Exceptionless.Logging.LogLevel.Debug;
break;
}
var eventBuilder = ExceptionlessClient.Default
.CreateLog(message, exlessLogLevel)
.SetSource(source)
.SetException(exception); if (eventId != null)
eventBuilder.SetProperty("Event", $"{eventId.ToString()}"); var serverAndPoint = LoggingUtility.GetAddressIP();
if (!string.IsNullOrEmpty(serverAndPoint))
eventBuilder.SetProperty("ServerEndPoint", serverAndPoint); eventBuilder.Submit();
}
catch { }
} private class NoopDisposable : IDisposable
{
public void Dispose()
{
}
}
}
}
(2)实现ILoggerProvider
using Microsoft.Extensions.Logging; namespace Overt.Core.Logging
{
/// <summary>
/// LoggerProvider
/// </summary>
public class ExlessLoggerProvider : ILoggerProvider
{
/// <summary>
/// Contructor
/// </summary>
/// <param name="categoryName"></param>
/// <returns></returns>
public ILogger CreateLogger(string categoryName)
{
return new ExlessLogger(categoryName);
} /// <summary>
///
/// </summary>
public void Dispose()
{
}
}
}
(3)依赖注入
using Exceptionless;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using NLog.Extensions.Logging;
using Overt.Core.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq; namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionExtensions
{ #region ExLess
/// <summary>
/// 注入
/// </summary>
/// <param name="loggingBuilder"></param>
/// <param name="configFile"></param>
public static void AddExlessLogging(this IServiceProvider provider)
{
var configuration = provider.GetService<IConfiguration>();
var loggerFactory = provider.GetService<ILoggerFactory>(); var client = ExceptionlessClient.Default;
client.InitExlessTags(configuration);
client.Configuration.ReadFromConfiguration(configuration);
client.Configuration.ReadFromEnvironmentalVariables();
client.Configuration.UseInMemoryStorage();
client.Startup(); loggerFactory.AddProvider(new ExlessLoggerProvider());
} /// <summary>
/// 注入
/// </summary>
/// <param name="loggingBuilder"></param>
/// <param name="configFile"></param>
public static void AddExlessLogging(this IApplicationBuilder app)
{
var provider = app.ApplicationServices;
var configuration = provider.GetService<IConfiguration>();
var loggerFactory = provider.GetService<ILoggerFactory>(); app.UseExceptionless(configuration);
var client = ExceptionlessClient.Default;
client.InitExlessTags(configuration);
client.Configuration.UseInMemoryStorage(); loggerFactory.AddProvider(new ExlessLoggerProvider());
} /// <summary>
/// tags
/// </summary>
/// <param name="client"></param>
/// <param name="configuration"></param>
private static void InitExlessTags(this ExceptionlessClient client, IConfiguration configuration)
{
var tags = configuration?["Exceptionless:Tags"]?.Split(",", StringSplitOptions.RemoveEmptyEntries)?.ToList();
foreach (var tag in tags ?? new List<string>())
{
client.Configuration.DefaultTags.Add(tag);
}
}
#endregion
}
}
5. 最终效果
可实时查看日志信息

NetCore微服务实战体系:日志管理的更多相关文章
- ASP.NET Core微服务实战系列
希望给你3-5分钟的碎片化学习,可能是坐地铁.等公交,积少成多,水滴石穿,码字辛苦,如果你吃了蛋觉得味道不错,希望点个赞,谢谢关注. 前言 这里记录的是个人奋斗和成长的地方,该篇只是一个系列目录和构想 ...
- 微服务实战(二):使用API Gateway - DockOne.io
原文:微服务实战(二):使用API Gateway - DockOne.io [编者的话]本系列的第一篇介绍了微服务架构模式.它讨论了采用微服务的优点和缺点,除了一些复杂的微服务,这种模式还是复杂应用 ...
- 微服务实战(一):微服务架构的优势与不足 - DockOne.io
原文:微服务实战(一):微服务架构的优势与不足 - DockOne.io [编者的话]本文来自Nginx官方博客,是微服务系列文章的第一篇,主要探讨了传统的单体式应用的不足,以及微服务架构的优势与挑战 ...
- Spring Cloud 微服务实战笔记
Spring Cloud 微服务实战笔记 微服务知识 传统开发所有业务逻辑都在一个应用中, 开发,测试,部署随着需求增加会不断为单个项目增加不同业务模块:前端展现也不局限于html视图模板的形式,后端 ...
- .Net微服务实战之可观测性
系列文章 .Net微服务实战之技术选型篇 .Net微服务实战之技术架构分层篇 .Net微服务实战之DevOps篇 .Net微服务实战之负载均衡(上) .Net微服务实战之CI/CD .Net微服务实战 ...
- go-zero微服务实战系列(三、API定义和表结构设计)
前两篇文章分别介绍了本系列文章的背景以及根据业务职能对商城系统做了服务的拆分,其中每个服务又可分为如下三类: api服务 - BFF层,对外提供HTTP接口 rpc服务 - 内部依赖的微服务,实现单一 ...
- 微服务实战(三):落地微服务架构到直销系统(构建基于RabbitMq的消息总线)
从前面文章可以看出,消息总线是EDA(事件驱动架构)与微服务架构的核心部件,没有消息总线,就无法很好的实现微服务之间的解耦与通讯.通常我们可以利用现有成熟的消息代理产品或云平台提供的消息服务来构建自己 ...
- 微服务实战(二):使用API Gateway
微服务实战(一):微服务架构的优势与不足 微服务实战(二):使用API Gateway 微服务实战(三):深入微服务架构的进程间通信 微服务实战(四):服务发现的可行方案以及实践案例 微服务实践(五) ...
- Spring Cloud微服务实战阅读笔记(一) 基础知识
本文系<Spring Cloud微服务实战>作者:翟永超,一书的阅读笔记. 一:基础知识 1:什么是微服务架构 是一种架构设计风格,主旨是将一个原本独立的系统拆分成多个小型服务 ...
随机推荐
- DES算法的python3实现
DES原理 DES原理 这里不予以复述, 有很多优秀的博客 原理可以参考这篇博客 https://www.cnblogs.com/songwenlong/p/5944139.html DES实现 1. ...
- vue.js中 v-for,v-on,v-model,结合应用案例---记事本
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- 从udaf谈flink的state
1.前言 本文主要基于实践过程中遇到的一系列问题,来详细说明Flink的状态后端是什么样的执行机制,以理解自定义函数应该怎么写比较合理,避免踩坑. 内容是基于Flink SQL的使用,主要说明自定义聚 ...
- Centos+Nginx部署Vue项目
1.项目打包生成dist文件夹 在项目根目录下打开cmd窗口,输入命令 npm run build //生成dist文件夹 2.将dist文件夹上传到centos7 使用scp命令或者用远程连接工具将 ...
- 利用 Github Actions 自动更新 docfx 文档
利用 Github Actions 自动更新 docfx 文档 Intro docfx 是微软出品一个 .NET API 文档框架,有一个理念是代码即文档,会根据项目代码自动生成 API 文档,即使没 ...
- [Hei-Ocelot-Gateway ].Net Core Api网关Ocelot的开箱即用版本
写在前面 很多neter都有在用Ocelot做Api网关,但是Ocelot又不像kong或者其他网关一样,开箱即用.它需要你单独开一个web项目来部署,这样很多同学都在做重复的事了. 这里[Hei.O ...
- MySQL是如何实现事务的ACID
前言 最近在面试,有被问到,MySQL的InnoDB引擎是如何实现事务的,又或者说是如何实现ACID这几个特性的,当时没有答好,所以自己总结出来,记录一下. 事务的四大特性ACID 事务的四大特性AC ...
- java+opencv实现人脸识别程序记录
结果 基本实现了识别的功能.基本的界面如下 界面长得比较丑,主要是JavaSwing写界面比较麻烦,写个菜单栏都要那么多代码.目前不打算改了. 实现的思路是:使用opencv中自带的OpenCVFra ...
- pandas 数据类型转换及描述统计
处理数据的时候往往需要对原始数据进行类型转换和预览等操作,下面介绍常用的处理预览和数据转换方法 预览:例: import pandas as pdsec_weather = pd.read_table ...
- python 递归删除空文件夹
Python如何递归删除空文件夹 1.Python如何递归删除空文件夹,这个问题很常见.但大多数人的解决办法都是自己实现递归函数解决这个问题,其实根本不用那么麻烦.Python中的os.walk提供了 ...