ASP .NET Core 集成 Exceptionless 日志

Exceptionless简介

Exceptionless是一款分布式日志管理框架,它可以统一收集管理并展示出来程序的日志,这样的话减少了传统开发过程中还需要去服务器查找日志的痛苦,大大提升对程序的运维效率。 Exceptionless依赖于Redis和Elasticsearch。

官网地址:https://exceptionless.com/
官方文档地址:https://exceptionless.com/docs/
官方Github地址:https://github.com/exceptionless/Exceptionless
Docker镜像地址:https://hub.docker.com/r/exceptionless/exceptionless
日志搜索文档:https://exceptionless.com/docs/filtering-and-searching

目前支持JavaScript, Node, .NET Core, .NET相关应用程序的异常信息采集。为何仅支持.Net .Net Core和JS相关的?原因很简单,Exceptionless是基于.NET Core开发的。如果你有别的语言的开发需求也想使用Exceptionless,这个时候不要气馁,因为Exceptionless本质是基于http接口的形式上报数据的,这个可在官方文档上找到如何使用http上报日志信息相关

官方文档api地址:https://exceptionless.com/docs/api/api-getting-started/
api官方文档地址:https://api.exceptionless.io/
api官方swagger地址:https://api.exceptionless.io/docs/index.html

部署Exceptionless

官网提供了两种使用的方式

  • 在官方网站注册账号然后获取apiKey,这样的话不用自己搭建Exceptionless,而是将日志直接收集上报到Exceptionless服务器上。但是,一般基于安全和性能考虑,这种方式并不常用。
  • 自建Exceptionless服务,也是本篇我们要使用的方式。之前的低版本支持在window服务器上自建服务,但是高版本已经是基于docker的方式构建了。而使用docker的方式也是我个人日常学习中比较喜欢的方式。

基于docker-compose部署。官方yml文件地址

https://github.com/exceptionless/Exceptionless/blob/main/docker-compose.yml
https://github.com/exceptionless/Exceptionless/blob/main/samples/docker-compose.yml

简化版docker-compose.yml

version: '3.7'

services:
  app:
    depends_on:
      - elasticsearch
    image: exceptionless/app:7.2.1
    environment:
      EX_AppMode: Production
      EX_ConnectionStrings__Cache: provider=redis
      EX_ConnectionStrings__Elasticsearch: server=http://elasticsearch:9200
      EX_ConnectionStrings__MessageBus: provider=redis
      EX_ConnectionStrings__Queue: provider=redis
      EX_ConnectionStrings__Redis: server=192.168.1.5:6379,abortConnect=false
      EX_RunJobsInProcess: 'false'
    ports:
      - 5000:80
    volumes:
      - appdata:/app/storage

  jobs:
    depends_on:
      - app
    image: exceptionless/job:7.2.1
    environment:
      EX_AppMode: Production
      EX_BaseURL: http://192.168.1.5:5000
      EX_ConnectionStrings__Cache: provider=redis
      EX_ConnectionStrings__Elasticsearch: server=http://elasticsearch:9200
      EX_ConnectionStrings__MessageBus: provider=redis
      EX_ConnectionStrings__Queue: provider=redis
      EX_ConnectionStrings__Redis: server=192.168.1.5:6379,abortConnect=false
      EX_ConnectionStrings__Storage: provider=folder;path=/app/storage
    volumes:
      - appdata:/app/storage

  elasticsearch:
    image: exceptionless/elasticsearch:7.15.2
    environment:
      discovery.type: single-node
      xpack.security.enabled: 'false'
      xpack.ml.enabled: 'false'
      ES_JAVA_OPTS: -Xms1g -Xmx1g
    ports:
      - 9200:9200
      - 9300:9300
    volumes:
      - esdata7:/usr/share/elasticsearch/data

volumes:
  esdata7:
    driver: local
  appdata:
    driver: local

yml下载到服务器后直接docker-compose up -d启动站点

Exceptionless 使用

访问站点http://192.168.1.5:5000/,首次登陆使用注册邮箱账号

注册成功后登陆就可以看到主界面了

新建一个组织

组织中新建一个项目,项目与组织绑定关系是为了后续组织邀请其他用户方便管理查看日志


输入项目名称

项目类型选择ASP.NET Core,然后选择管理项目

进入项目详情,选择API秘钥,在ASP.NET Core项目中需要此秘钥配置

ASP .NET Core 集成 Exceptionless

appsettings.json添加Exceptionless配置

"Exceptionless": {
    "ServerUrl": "http://192.168.1.5:5000",
    "ApiKey": "2oWkeKEw0gKqb4gu2vsMvr4b3mK1V47fshjaYyJ2"
}

使用官方包集成

Neget安装包

Exceptionless.AspNetCore

Startup.cs添加配置

services.AddExceptionless(Configuration);
//或者
//ExceptionlessClient.Default.Configuration.ApiKey = Configuration["ExceptionLess:ApiKey"];
//ExceptionlessClient.Default.Configuration.ServerUrl = Configuration["ExceptionLess:ServerUrl"];

services.AddSingleton<ILogger, ExceptionLessLogger>();

app.UseExceptionless();

或者ConfigureExceptionlessExtensions添加

using Exceptionless;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace ConsoleApp1
{
    public static class ConfigureExceptionlessExtensions
    {
        private static string ServerName = "";

        public static void ConfigureExceptionless(this IServiceCollection services, IConfiguration configuration)
        {
            string apiKey = configuration["exceptionless:ApiKey"];
            string serverUrl = configuration["exceptionless:ServerUrl"];
            ServerName = configuration["GlobalTags:server"];
            if (!string.IsNullOrWhiteSpace(apiKey) && !string.IsNullOrWhiteSpace(serverUrl))
            {
                ExceptionlessClient.Default.Configuration.ApiKey = apiKey;
                ExceptionlessClient.Default.Configuration.ServerUrl = serverUrl;
                //事件添加Tag
                ExceptionlessClient.Default.SubmittingEvent += Default_SubmittingEvent;
            }
        }

        private static void Default_SubmittingEvent(object sender, EventSubmittingEventArgs e)
        {
            if (!string.IsNullOrWhiteSpace(ServerName)) e.Event.Tags.Add(ServerName);
        }
    }
}

添加日志

ExceptionlessClient.Default.CreateLog("GUID", LogLevel.Warn).AddTags("tag").Submit();

扩展日志帮助类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Exceptionless;
using Exceptionless.Logging;

namespace ExceptionlessDemo
{

    public static class Extensions
    {
        /// <summary>
        /// 跟踪
        /// </summary>
        public static void TraceExceptionless(this Microsoft.Extensions.Logging.ILogger log, string message, params string[] tags)
        {
            ExceptionlessClient.Default.CreateLog(message, LogLevel.Trace).AddTags(tags).Submit();
        }

        /// <summary>
        /// 信息
        /// </summary>
        public static void InfoExceptionless(this ILogger log, string message, params string[] tags)
        {
            ExceptionlessClient.Default.CreateLog(message, LogLevel.Info).AddTags(tags).Submit();
        }

        /// <summary>
        /// 警告
        /// </summary>
        public static void WarnExceptionless(this Microsoft.Extensions.Logging.ILogger log, string message, params string[] tags)
        {
            ExceptionlessClient.Default.CreateLog(message, LogLevel.Warn).AddTags(tags).Submit();
        }

        /// <summary>
        /// 错误
        /// </summary>
        public static void ErrorExceptionless(this ILogger log, string message, params string[] tags)
        {
            ExceptionlessClient.Default.CreateLog(message, LogLevel.Error).AddTags(tags).Submit();
        }

        /// <summary>
        /// 错误
        /// </summary>
        public static void ErrorExceptionless(this Microsoft.Extensions.Logging.ILogger log, Exception exception, params string[] tags)
        {
            ExceptionlessClient.Default.CreateException(exception).AddTags(tags).Submit();
        }
    }


    public interface ILogger
    {
        void Trace(string message, params string[] args);
        void Debug(string message, params string[] args);
        void Info(string message, params string[] args);
        void Warn(string message, params string[] args);
        void Error(string message, params string[] args);
        void Error(Exception ex, params string[] args);
    }

    public class ExceptionLessLogger : ILogger
    {
        /// <summary>
        /// Trace
        /// </summary>
        public void Trace(string message, params string[] tags)
        {
            ExceptionlessClient.Default.CreateLog(message, LogLevel.Trace).AddTags(tags).Submit();
        }

        /// <summary>
        /// Debug
        /// </summary>
        public void Debug(string message, params string[] tags)
        {
            ExceptionlessClient.Default.CreateLog(message, LogLevel.Debug).AddTags(tags).Submit();
        }

        /// <summary>
        /// Info
        /// </summary>
        public void Info(string message, params string[] tags)
        {
            ExceptionlessClient.Default.CreateLog(message, LogLevel.Info).AddTags(tags).Submit();
        }

        /// <summary>
        /// Warn
        /// </summary>
        public void Warn(string message, params string[] tags)
        {
            ExceptionlessClient.Default.CreateLog(message, LogLevel.Warn).AddTags(tags).Submit();
        }

        /// <summary>
        /// Error
        /// </summary>
        public void Error(string message, params string[] tags)
        {
            ExceptionlessClient.Default.CreateLog(message, LogLevel.Error).AddTags(tags).Submit();
        }

        /// <summary>
        /// 错误
        /// </summary>
        public void Error(Exception exception, params string[] tags)
        {
            ExceptionlessClient.Default.CreateException(exception).AddTags(tags).Submit();
        }
    }
    //日志Tags
    public static class LogTags
    {
        public const string LogTag = "TestProjectLogTag";
    }
}

Controllers发送日志

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ExceptionlessDemo.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        //建议使用 _logger2
        public ILogger<WeatherForecastController> Logger { get; set; }
        private readonly ILogger _logger2;
        public WeatherForecastController(ILogger<WeatherForecastController> logger, ILogger logger2)
        {
            _logger2 = logger2;
            Logger = logger;
            //Logger = NullLogger<WeatherForecastController>.Instance;
        }

        [HttpGet]
        public string Get()
        {
            Logger.WarnExceptionless("微软日志扩展", "LogInformation");
            _logger2.Debug("12321321", "Debug1");

            return Guid.NewGuid().ToString();
        }
    }
}

使用Serilog集成

Neget安装包

Serilog.AspNetCore
Serilog.Sinks.Exceptionless

Program.cs添加配置

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Serilog;
using Serilog.Events;
using System.Text;

namespace ExceptionlessDemo
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                })
                .UseSerilog(ConfigureSerilog);

        static void ConfigureSerilog(HostBuilderContext context, LoggerConfiguration logger)
        {
            var apiKey = context.Configuration["ExceptionLess:ApiKey"];
            var serverUrl = context.Configuration["ExceptionLess:ServerUrl"];

            logger
                .MinimumLevel.Information()
                .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
                .MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Warning)
                .Enrich.FromLogContext()
                //添加Exceptionless
                .WriteTo.Exceptionless(apiKey, serverUrl);
        }
    }
}

查看日志

参考文档

https://www.cnblogs.com/wucy/p/14401650.html
https://www.dongchuanmin.com/net/3230.html
posted @ 2022-11-12 14:31  雨水的命运  阅读(284)  评论(0编辑  收藏  举报