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:什么是微服务架构 是一种架构设计风格,主旨是将一个原本独立的系统拆分成多个小型服务 ...
随机推荐
- C#设计模式之4-原型模式
原型模式(Prototype Pattern) 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/395 访问. 原型模式属 ...
- 基于Linux系统geth的安装
转载地址 https://blog.csdn.net/qq_36124194/article/details/83658580 基于Linux系统geth的安装 安装ethereum sudo apt ...
- Android开发进程0.1 轮播图 Scrollview Fragment
轮播图的实现 轮播图通过banner可以较为便捷的实现 1.添加本地依赖,在dependence中搜索相关依赖 2.添加banner的view组件 3.创建适配器GlideImageLoader ex ...
- Python Unofficial Windows Binary
python一些安装包有时候在windows下无法 直接安装. 可以在一个非官方的Python Windows扩展库里面找到对应的打包好的whl,下载后直接安装. https://www.lfd.uc ...
- offer收割机也有方法论
秋招的战火就像这夏天的温度一样炙热,陆陆续续很多学弟学妹问我秋招的注意事项,作为温暖型大叔的我此刻必须出场了. 看仔细了,接下来龙叔就把这offer收割机的秘密都告诉你们. 如果你还没点关注的话,记得 ...
- HotSpot的执行引擎-CallStub栈帧
之前多次提到接触到调用JavaCalls::call()方法来执行Java方法,如: (1)Java主类装载时,调用JavaCalls::call()方法执行的Java方法checkAndLoadMa ...
- CopyOnWriteArrayList源码阅读笔记
简介 ArrayList是开发中使用比较多的集合,它不是线程安全的,CopyOnWriteArrayList就是线程安全版本的ArrayList.CopyOnWriteArrayList同样是通过数组 ...
- JavaScript学习系列博客_31_JavaScript Math 工具类
Math - Math属于一个工具类,它不需要我们创建对象(例如Date日期对象需要通过构造函数创建对象 var 变量=new Date(),Math不需要),它里边封装了属性运算相关的常量和方法 我 ...
- 封装Vue Element的form表单组件
前两天封装了一个基于vue和Element的table表格组件,阅读的人还是很多的,看来大家都是很认同组件化.高复用这种开发模式的,毕竟开发效率高,代码优雅,逼格高嘛.虽然这两天我的心情很糟糕,就像& ...
- gorm demo
package main import ( "fmt" "github.com/jinzhu/gorm" _ "github.com/jinzhu/g ...