c# - Microsoft Service Fabric 和日志记录

标签 c# logging .net-core azure-service-fabric

我正在研究为我的 Service Fabric 无状态 API 实现日志记录的最佳方法,但对于看似相对简单的要求的各种不同解决方案,我感到有些不知所措。

我已经使用 WebHostBuilder().ConfigureLogging 实现了日志记录,并通过 Serilog.Extensions.Logging.File 成功地将我的跟踪消息记录到调试窗口还设法将此日志转储到一个文件中,这一切都是通过 #if DEBUG 指令控制的,我对此很满意。

然后我需要配置部署到 Azure 中的集群时会发生什么,这让我不知所措!!!

我以为我可以像使用 AddDebug 一样注册 ServiceEventSource 类型的记录器,但它并没有这么简单。

所以我已经设法让我的日志出现在使用 ServiceEventSource.Current.Message 的诊断窗口中,但是这些日志没有集成在 ASP.NET 日志记录框架中:/

我的持续调查使我了解到 Service Fabric 日志记录应该针对 Application Insights,尽管许多文章对最新框架的详细程度和适用性各不相同。

我目前的想法是我需要删除 ASP.NET 日志记录并实现诸如 EventFlow 之类的东西,以允许生成我的跟踪消息并随后通过管道传输到 Application Insights 以便稍后进行查询date,我的想法对吗??

或者我目前正在切线?

最佳答案

2019 年 5 月 15 日更新
将此部署到 Azure Service Fabric 后,日志文件未填充,这似乎是 Serilog.Sinks.AzureBlobStorage NUGET 包与我的项目所针对的 .NET Core 2.2.0 版之间的不兼容.

我已经在 GitHub 页面上发布了一张票并等待回复,短期内您可以下载源代码并将项目迁移到 Microsoft.NETCore.App 2.2.0 项目和直接引用它,一切正常。

原始答案
我似乎经常这样做,回答我自己的问题,但又来了。我花了一两天时间才弄清楚这个问题,所以我想我会与社区分享我的发现和解决方案,以防它可能在未来帮助其他人和/或有人可能有一些补充甚至矛盾我欢迎任何意见。

我的开发环境如下:-

Microsoft Visual Studio 15.9.11
Windows 10 专业版 SDK:Microsoft.NETCore.App 2.2.0

我创建了一个新的 Service Fabric 无状态服务,该服务的目的是为 Angular 7 前端 Web 应用程序提供 RESTful 端点。

我的要求是通过调试窗口在我的开发环境中提供日志记录信息,并在我的应用程序托管在 Azure 上的 Service Fabric 集群中时提供类似的日志记录信息。

NUGET 包安装
Microsoft.Extensions.Logging (2.2.0)
Serilog.AspNetCore (2.1.1)
Serilog.Enrichers.Environment (2.1.3)
Serilog.Settings.Configuration (3.0.1)
Serilog.Sinks.Debug (1.0.1)
Serilog.Sinks.AzureBlobStorage (1.3.0)

控制开发和生产环境
我使用 DEBUG 预处理器指令控制开发和生产环境,以包含 appsettings.jsonappsettings.Development.json 文件。

我的 appSettings.Development.json 文件是这样的:-

{
  "AppSettings": {
     // My app settings not applicable to this
  },
  "Serilog": {
    "Using": [ "Serilog.Sinks.Debug" ],
    "MinimumLevel": {
      "Default": "Verbose",
      "Override": {
        "Microsoft": "Warning",
        "System": "Warning"
      }
    },
    "WriteTo": [
      {
        "Name": "Debug",
        "Args": {
          "outputTemplate": "[{Timestamp:HH:mm:ss} {MachineName} {Level:u3}] {Message:lj}{NewLine}{Exception}"
        }
      }
    ],
    "Enrich": ["WithMachineName"]
  } 
}

我的 appSettings.json 文件是这样的:-

{
  "AppSettings": {
     // My app settings not applicable to this
  },
  "Serilog": {
    "Using": [ "Serilog.Sinks.AzureBlobStorage" ],
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Microsoft": "Warning",
        "System": "Warning"
      }
    },
    "WriteTo": [
      {
        "Name": "AzureBlobStorage",
        "Args": {
          "outputTemplate": "[{Timestamp:HH:mm:ss} {MachineName} {Level:u3}] {Message:lj}{NewLine}{Exception}",
          "connectionString": "[Connection String]",
          "storageContainerName": "app",
          "storageFileName": "{yyyy}-{MM}-{dd}.log"
        }
      }
    ],
    "Enrich": [ "WithMachineName" ]
  }
}

正如您从上面的设置文件中看到的那样,我在开发时输出到调试窗口,并且我选择在部署到 Azure 中的 Service Fabric 集群时输出到 Azure Blob 存储。

要实现 Serilog 日志记录,请简单查看下面我的无状态服务类实现,它显示了如何根据环境切换两个不同的 appSettings.json 文件,以及如何通过使用将 Serilog 记录器插入依赖注入(inject)系统UseSerilog 扩展方法。

using System.Collections.Generic;
using System.Fabric;
using System.IO;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.ServiceFabric.Services.Communication.AspNetCore;
using Microsoft.ServiceFabric.Services.Communication.Runtime;
using Microsoft.ServiceFabric.Services.Runtime;
using Serilog;

namespace Caboodal.Manatee.ServiceFabric.Api.Identity
{
    internal sealed class Identity : StatelessService
    {
        public Identity(StatelessServiceContext context)
            : base(context)
        {
        }

        private string AppSettingsFilename
        {
            get
            {
#if DEBUG
                return "appsettings.Development.json";
#else
                return "appsettings.json";
#endif
            }
        }

        protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
        {
            var appSettings = GetAppSettings();

            Log.Logger = new LoggerConfiguration()
                .ReadFrom.Configuration(appSettings)
                .CreateLogger();

            return new[]
            {
                new ServiceInstanceListener(
                    serviceContext =>
                        new KestrelCommunicationListener(
                            serviceContext,
                            "ServiceEndpoint",
                            (url, listener) =>
                            {
                                ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting Kestrel on {url}");

                                return new WebHostBuilder()
                                    .UseKestrel()
                                    .ConfigureAppConfiguration(
                                        (builderContext, config) =>
                                        {
                                            config.AddJsonFile(AppSettingsFilename, false, true);
                                        })
                                    .ConfigureServices(
                                        services => services
                                            .AddSingleton(serviceContext))
                                    .UseContentRoot(Directory.GetCurrentDirectory())
                                    .UseSerilog()
                                    .UseStartup<Startup>()
                                    .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
                                    .UseUrls(url)
                                    .Build();
                            }))
            };
        }

        private IConfigurationRoot GetAppSettings()
        {
            return new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile(AppSettingsFilename)
                .Build();
        }
    }
}

在 Controller 中使用记录器
因为 ILogger 实例被配置为依赖注入(inject)实例,所以它可以像任何其他依赖项一样在您的 Controller 类中简单地访问,例如

    [Authorize]
    [ApiController]
    [Route("[controller]")]
    public class UserController : ApiController
    {
        private readonly IUserService _userService;
        private readonly ILogger<UserController> _logger;

        public UserController(IUserService userService, ILogger<UserController> logger)
        {
            _userService = userService;
            _logger = logger;
        }

        [AllowAnonymous]
        [HttpPost("authenticate")]
        public IActionResult Authenticate([FromBody] DtoAuthenticateRequest request)
        {
            // Adding log entries
            _logger.Log(LogLevel.Debug, "Here is a log entry");

            // Some code in here
            return Ok(response);
        }
    }

ServiceEventSource.cs 类让我分心了,但由于使用了 Serilog,我现在忽略了项目模板的这一方面。

如果您希望将您的日志输出给其他数据消费者或只是输出不同的格式,那么只需查看 Serilog 网站 here获取可用接收器的完整列表,Application Insights 是众多接收器之一。

关于c# - Microsoft Service Fabric 和日志记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56062875/

相关文章:

c# - DateTime 销毁 View

c# - "///<exclude/>"是什么意思?

pdf - 在Net Core中解析pdf

c# - 如何调用.Net Framework中的函数到.Net core

logging - 使用 grep 过滤命令输出

c# - 使用 HTTPGET 读取和操作文本文件

c# -ModelState.IsValid 仅在资源语言更改时返回 false?

c# - 将文件中的十六进制添加到 List<byte>

java - 使用 Spring-Boot 的 Logback 配置实时重新加载 (scan=true)

java - 在 Logback 中以编程方式引用预先存在的附加程序的正确方法是什么?