@@ -40,22 +40,15 @@ namespace HealthMonitor.Service.Biz.db | |||||
short port = _configTDengineService.Port; | short port = _configTDengineService.Port; | ||||
string password = _configTDengineService.Password; | string password = _configTDengineService.Password; | ||||
IntPtr conn = TDengine.Connect(host, user, password, db, port); | IntPtr conn = TDengine.Connect(host, user, password, db, port); | ||||
//string host = "172.16.255.180"; | |||||
//short port = 6030; | |||||
//string user = "root"; | |||||
//string password = "taosdata"; | |||||
//string db = "health_monitor"; | |||||
//IntPtr conn = TDengine.Connect(host, user, password, db, port); | |||||
// Check if get connection success | |||||
if (conn == IntPtr.Zero) | if (conn == IntPtr.Zero) | ||||
{ | { | ||||
Console.WriteLine("Connect to TDengine failed"); | |||||
_logger.LogError($"连接 TDengine 失败...."); | |||||
// Console.WriteLine("Connect to TDengine failed"); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
Console.WriteLine("Connect to TDengine success"); | |||||
_logger.LogInformation($"连接 TDengine 成功...."); | |||||
// Console.WriteLine("Connect to TDengine success"); | |||||
} | } | ||||
return conn; | return conn; | ||||
} | } | ||||
@@ -64,6 +64,10 @@ namespace HealthMonitor.Service.Cache | |||||
catch (Exception ex) | catch (Exception ex) | ||||
{ | { | ||||
Console.WriteLine(ex.ToString() ); | Console.WriteLine(ex.ToString() ); | ||||
// _logger.LogError($"连接 TDengine 成功...."); | |||||
_logger.LogError($"{nameof(GetBloodPressReferenceValueAsync)}发生异常:{ex.Message}, {ex.StackTrace}"); | |||||
return new HmBloodPressReferenceValue | return new HmBloodPressReferenceValue | ||||
{ | { | ||||
Age = 0, | Age = 0, | ||||
@@ -8,6 +8,7 @@ using HealthMonitor.Service.Resolver.Interface; | |||||
using HealthMonitor.Service.Sub.Topic.Model; | using HealthMonitor.Service.Sub.Topic.Model; | ||||
using Microsoft.Extensions.Logging; | using Microsoft.Extensions.Logging; | ||||
using Microsoft.Extensions.Options; | using Microsoft.Extensions.Options; | ||||
using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
using System; | using System; | ||||
using System.Collections.Concurrent; | using System.Collections.Concurrent; | ||||
@@ -88,11 +89,12 @@ namespace HealthMonitor.Service.Sub | |||||
if (conn == IntPtr.Zero) | if (conn == IntPtr.Zero) | ||||
{ | { | ||||
_logger.LogError("reason:" + TDengine.Error(conn)); | _logger.LogError("reason:" + TDengine.Error(conn)); | ||||
throw new Exception("Connect to TDengine failed"+DateTime.Now.ToString()); | |||||
//throw new Exception("Connect to TDengine failed"+DateTime.Now.ToString()); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
Console.WriteLine("Connect to TDengine success"); | |||||
_logger.LogInformation($"连接 TDengine 成功...."); | |||||
//Console.WriteLine("Connect to TDengine success"); | |||||
} | } | ||||
DoReceive(conn); | DoReceive(conn); | ||||
} | } | ||||
@@ -116,7 +118,7 @@ namespace HealthMonitor.Service.Sub | |||||
string attributes = ""; | string attributes = ""; | ||||
foreach (PropertyInfo prop in props) | foreach (PropertyInfo prop in props) | ||||
{ | { | ||||
JsonPropertyAttribute attr = prop.GetCustomAttribute<JsonPropertyAttribute>(); | |||||
JsonPropertyAttribute attr = prop.GetCustomAttribute<JsonPropertyAttribute>()!; | |||||
if (attr != null) | if (attr != null) | ||||
{ | { | ||||
attributes += attr.PropertyName + ","; | attributes += attr.PropertyName + ","; | ||||
@@ -171,14 +173,16 @@ namespace HealthMonitor.Service.Sub | |||||
} | } | ||||
catch (Exception ex) | catch (Exception ex) | ||||
{ | { | ||||
Console.WriteLine(ex.Message); | |||||
_logger.LogError($"解析包发生异常:{ex.Message}, {ex.StackTrace}"); | |||||
// Console.WriteLine(ex.Message); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
consumer.Commit(consumeRes); | consumer.Commit(consumeRes); | ||||
Console.WriteLine("监听中...."); | |||||
// Console.WriteLine("监听中...."); | |||||
_logger.LogInformation($"监听中...."); | |||||
} | } | ||||
// close consumer after use.Otherwise will lead memory leak. | // close consumer after use.Otherwise will lead memory leak. | ||||
@@ -0,0 +1,28 @@ | |||||
using Serilog; | |||||
using Serilog.Configuration; | |||||
using Serilog.Core; | |||||
using Serilog.Events; | |||||
using System; | |||||
using System.Threading; | |||||
namespace HealthMonitor.WebApi.Configs | |||||
{ | |||||
public class ThreadInfoEnricher : ILogEventEnricher | |||||
{ | |||||
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) | |||||
{ | |||||
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("ThreadId", Thread.CurrentThread.ManagedThreadId)); | |||||
} | |||||
} | |||||
public static class EnricherExtensions | |||||
{ | |||||
public static LoggerConfiguration WithThreadInfo(this LoggerEnrichmentConfiguration enrich) | |||||
{ | |||||
if (enrich == null) | |||||
throw new ArgumentNullException(nameof(enrich)); | |||||
return enrich.With<ThreadInfoEnricher>(); | |||||
} | |||||
} | |||||
} |
@@ -8,6 +8,8 @@ | |||||
<ItemGroup> | <ItemGroup> | ||||
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" /> | <PackageReference Include="Serilog.AspNetCore" Version="3.4.0" /> | ||||
<PackageReference Include="Serilog.Expressions" Version="3.4.0" /> | |||||
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" /> | |||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" /> | <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" /> | ||||
<PackageReference Include="TelpoDataService.Util" Version="1.6.9.16-beta1" /> | <PackageReference Include="TelpoDataService.Util" Version="1.6.9.16-beta1" /> | ||||
</ItemGroup> | </ItemGroup> | ||||
@@ -0,0 +1,38 @@ | |||||
using Microsoft.Extensions.Http; | |||||
using Microsoft.Extensions.Http.Logging; | |||||
using Microsoft.Extensions.Logging; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
namespace HealthMonitor.WebApi.HttpLog | |||||
{ | |||||
public class CustomLoggingFilter : IHttpMessageHandlerBuilderFilter | |||||
{ | |||||
private readonly ILoggerFactory _loggerFactory; | |||||
public CustomLoggingFilter(ILoggerFactory loggerFactory) | |||||
{ | |||||
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); | |||||
} | |||||
public Action<HttpMessageHandlerBuilder> Configure(Action<HttpMessageHandlerBuilder> next) | |||||
{ | |||||
if (next == null) | |||||
{ | |||||
throw new ArgumentNullException(nameof(next)); | |||||
} | |||||
return (builder) => | |||||
{ | |||||
// Run other configuration first, we want to decorate. | |||||
next(builder); | |||||
var outerLogger = _loggerFactory.CreateLogger($"HttpClient.{builder.Name}.LogicalHandler"); | |||||
//builder.AdditionalHandlers.Insert(0, new CustomLoggingScopeHttpMessageHandler(outerLogger)); | |||||
builder.AdditionalHandlers.Insert(0, new LoggingScopeHttpMessageHandler(outerLogger)); | |||||
}; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,100 @@ | |||||
using Microsoft.Extensions.Logging; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Net; | |||||
using System.Net.Http; | |||||
using System.Text; | |||||
using System.Threading; | |||||
using System.Threading.Tasks; | |||||
namespace HealthMonitor.WebApi.HttpLog | |||||
{ | |||||
public class CustomLoggingScopeHttpMessageHandler : DelegatingHandler | |||||
{ | |||||
private readonly ILogger _logger; | |||||
public CustomLoggingScopeHttpMessageHandler(ILogger logger) | |||||
{ | |||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); | |||||
} | |||||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, | |||||
CancellationToken cancellationToken) | |||||
{ | |||||
if (request == null) | |||||
{ | |||||
throw new ArgumentNullException(nameof(request)); | |||||
} | |||||
using (Log.BeginRequestPipelineScope(_logger, request)) | |||||
{ | |||||
Log.RequestPipelineStart(_logger, request); | |||||
var response = await base.SendAsync(request, cancellationToken); | |||||
Log.RequestPipelineEnd(_logger, response); | |||||
return response; | |||||
} | |||||
} | |||||
private static class Log | |||||
{ | |||||
private static class EventIds | |||||
{ | |||||
public static readonly EventId PipelineStart = new EventId(100, "RequestPipelineStart"); | |||||
public static readonly EventId PipelineEnd = new EventId(101, "RequestPipelineEnd"); | |||||
} | |||||
private static readonly Func<ILogger, HttpMethod, Uri, string, IDisposable> _beginRequestPipelineScope = | |||||
LoggerMessage.DefineScope<HttpMethod, Uri, string>( | |||||
"HTTP {HttpMethod} {Uri} {CorrelationId}"); | |||||
private static readonly Action<ILogger, HttpMethod, Uri, string, Exception> _requestPipelineStart = | |||||
LoggerMessage.Define<HttpMethod, Uri, string>( | |||||
LogLevel.Information, | |||||
EventIds.PipelineStart, | |||||
"Start processing HTTP request {HttpMethod} {Uri} [Correlation: {CorrelationId}]"); | |||||
private static readonly Action<ILogger, HttpStatusCode, Exception> _requestPipelineEnd = | |||||
LoggerMessage.Define<HttpStatusCode>( | |||||
LogLevel.Information, | |||||
EventIds.PipelineEnd, | |||||
"End processing HTTP request - {StatusCode}"); | |||||
public static IDisposable BeginRequestPipelineScope(ILogger logger, HttpRequestMessage request) | |||||
{ | |||||
var correlationId = GetCorrelationIdFromRequest(request); | |||||
return _beginRequestPipelineScope(logger, request.Method, request.RequestUri, correlationId); | |||||
} | |||||
public static void RequestPipelineStart(ILogger logger, HttpRequestMessage request) | |||||
{ | |||||
if (logger.IsEnabled(LogLevel.Trace)) | |||||
{ | |||||
var correlationId = GetCorrelationIdFromRequest(request); | |||||
_requestPipelineStart(logger, request.Method, request.RequestUri, correlationId, null); | |||||
} | |||||
} | |||||
public static void RequestPipelineEnd(ILogger logger, HttpResponseMessage response) | |||||
{ | |||||
if (logger.IsEnabled(LogLevel.Trace)) | |||||
{ | |||||
_requestPipelineEnd(logger, response.StatusCode, null); | |||||
} | |||||
} | |||||
private static string GetCorrelationIdFromRequest(HttpRequestMessage request) | |||||
{ | |||||
var correlationId = "Not set"; | |||||
if (request.Headers.TryGetValues("X-Correlation-ID", out var values)) | |||||
{ | |||||
correlationId = values.First(); | |||||
} | |||||
return correlationId; | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -21,6 +21,7 @@ namespace HealthMonitor.WebApi | |||||
public async Task<bool> ResolveAsync() | public async Task<bool> ResolveAsync() | ||||
{ | { | ||||
var resolver = _msgQueueManager.GetMsgResolver(); | var resolver = _msgQueueManager.GetMsgResolver(); | ||||
try | try | ||||
{ | { | ||||
@@ -33,7 +34,7 @@ namespace HealthMonitor.WebApi | |||||
catch (Exception ex) | catch (Exception ex) | ||||
{ | { | ||||
Console.WriteLine(ex.Message); | |||||
//Console.WriteLine(ex.Message); | |||||
_logger.LogError($"未处理异常 message: {ex.Message}\n {ex.StackTrace}"); | _logger.LogError($"未处理异常 message: {ex.Message}\n {ex.StackTrace}"); | ||||
} | } | ||||
@@ -26,6 +26,11 @@ using HealthMonitor.Service.Sub; | |||||
using HealthMonitor.Service.Resolver; | using HealthMonitor.Service.Resolver; | ||||
using HealthMonitor.Service.Resolver.Factory; | using HealthMonitor.Service.Resolver.Factory; | ||||
using HealthMonitor.Service.Resolver.Interface; | using HealthMonitor.Service.Resolver.Interface; | ||||
using Serilog; | |||||
using Serilog.Core; | |||||
using HealthMonitor.WebApi.HttpLog; | |||||
using Microsoft.Extensions.Http; | |||||
using Microsoft.Extensions.DependencyInjection.Extensions; | |||||
namespace HealthMonitor.WebApi | namespace HealthMonitor.WebApi | ||||
{ | { | ||||
@@ -33,6 +38,17 @@ namespace HealthMonitor.WebApi | |||||
{ | { | ||||
public static void Main(string[] args) | public static void Main(string[] args) | ||||
{ | { | ||||
//选择配置文件appsetting.json | |||||
var config = new ConfigurationBuilder() | |||||
.SetBasePath(Directory.GetCurrentDirectory()) | |||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) | |||||
.Build(); | |||||
Log.Logger = new LoggerConfiguration() | |||||
.ReadFrom.Configuration(config).Enrich.WithThreadInfo() | |||||
.CreateLogger(); | |||||
var builder = WebApplication.CreateBuilder(args); | var builder = WebApplication.CreateBuilder(args); | ||||
// Add services to the container. | // Add services to the container. | ||||
@@ -176,8 +192,13 @@ namespace HealthMonitor.WebApi | |||||
.AddHostedService<Worker>(); | .AddHostedService<Worker>(); | ||||
#endregion | #endregion | ||||
builder.Host.UseSerilog(); | |||||
builder.Services.Replace(ServiceDescriptor.Singleton<IHttpMessageHandlerBuilderFilter, CustomLoggingFilter>()); | |||||
// Register the Swagger generator, defining 1 or more Swagger documents | // Register the Swagger generator, defining 1 or more Swagger documents | ||||
builder.Services.AddSwaggerGen(c => | builder.Services.AddSwaggerGen(c => | ||||
@@ -196,6 +217,8 @@ namespace HealthMonitor.WebApi | |||||
}); | }); | ||||
var app = builder.Build(); | var app = builder.Build(); | ||||
@@ -235,6 +258,7 @@ namespace HealthMonitor.WebApi | |||||
c.SwaggerEndpoint($"{sub}/{AppConsts.SWAGGER_DOC_HealthMonitor}/api-docs/", "HealthMonitor模块"); //分组显示 | c.SwaggerEndpoint($"{sub}/{AppConsts.SWAGGER_DOC_HealthMonitor}/api-docs/", "HealthMonitor模块"); //分组显示 | ||||
c.RoutePrefix = string.Empty; | c.RoutePrefix = string.Empty; | ||||
}); | }); | ||||
@@ -249,6 +273,7 @@ namespace HealthMonitor.WebApi | |||||
var csredisDb7 = new CSRedis.CSRedisClient(csredisDb7Con.ToString()); | var csredisDb7 = new CSRedis.CSRedisClient(csredisDb7Con.ToString()); | ||||
RedisHelperDb7.Initialization(csredisDb7); | RedisHelperDb7.Initialization(csredisDb7); | ||||
app.UseHttpsRedirection(); | app.UseHttpsRedirection(); | ||||
app.UseAuthorization(); | app.UseAuthorization(); | ||||
@@ -2,8 +2,124 @@ | |||||
"Logging": { | "Logging": { | ||||
"LogLevel": { | "LogLevel": { | ||||
"Default": "Information", | "Default": "Information", | ||||
"Microsoft.AspNetCore": "Warning" | |||||
"Microsoft": "Warning", | |||||
"Microsoft.Hosting.Lifetime": "Information", | |||||
"HttpClient": "Information" | |||||
} | } | ||||
}, | }, | ||||
"Serilog": { | |||||
"Using": [ "Serilog.Sinks.File", "Serilog.Sinks.Console", "Serilog.Expressions" ], | |||||
"MinimumLevel": { | |||||
"Default": "Information", | |||||
"Override": { | |||||
"Microsoft": "Warning", | |||||
"System": "Warning" | |||||
} | |||||
}, | |||||
"Enrich": [ | |||||
"FromLogContext", | |||||
"WithThreadId" | |||||
], | |||||
"WriteTo": [ | |||||
{ | |||||
"Name": "Console", | |||||
"Args": { | |||||
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level}] [Thread-{ThreadId}] [{SourceContext:l}] [{RequestId}]{NewLine}{Message}{NewLine}" | |||||
} | |||||
}, | |||||
{ | |||||
"Name": "Logger", | |||||
"Args": { | |||||
"ConfigureLogger": { | |||||
"WriteTo": [ | |||||
{ | |||||
"Name": "File", | |||||
"Args": { | |||||
"restrictedToMinimumLevel": "Information", | |||||
"path": "/var/health_monitor/logs/infos/info.log", | |||||
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level}] [Thread-{ThreadId}] [{SourceContext:l}] [{RequestId}] {Message}{NewLine}{Exception}", | |||||
//"fileSizeLimitBytes": 524288000, | |||||
"rollingInterval": "Day", | |||||
"rollOnFileSizeLimit": "true", | |||||
"retainedFileCountLimit": 7 | |||||
} | |||||
} | |||||
], | |||||
"Filter": [ | |||||
{ | |||||
"Name": "ByIncludingOnly", | |||||
"Args": { | |||||
"Expression": "@l = 'Information'" | |||||
} | |||||
} | |||||
] | |||||
} | |||||
} | |||||
}, | |||||
{ | |||||
"Name": "Logger", | |||||
"Args": { | |||||
"ConfigureLogger": { | |||||
"WriteTo": [ | |||||
{ | |||||
"Name": "File", | |||||
"Args": { | |||||
"RestrictedToMinimumLevel": "Warning", | |||||
"RollingInterval": "Day", | |||||
"RollOnFileSizeLimit": "true", | |||||
"OutputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff }[{Level:u3}] [Thread-{ThreadId}] [{SourceContext:l}] [{RequestId}] {Message:lj}{NewLine}", | |||||
"Path": "/var/health_monitor/logs/warnings/warn.log", | |||||
"RetainedFileCountLimit": 10 | |||||
} | |||||
} | |||||
], | |||||
"Filter": [ | |||||
{ | |||||
"Name": "ByIncludingOnly", | |||||
"Args": { | |||||
"Expression": "@l = 'Warning'" | |||||
} | |||||
} | |||||
] | |||||
} | |||||
} | |||||
}, | |||||
{ | |||||
"Name": "Logger", | |||||
"Args": { | |||||
"ConfigureLogger": { | |||||
"WriteTo": [ | |||||
{ | |||||
"Name": "File", | |||||
"Args": { | |||||
"restrictedToMinimumLevel": "Error", | |||||
"path": "/var/health_monitor/logs/errors/error.log", | |||||
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level}] [Thread-{ThreadId}] [{SourceContext:l}] [{RequestId}] {Message}{NewLine}{Exception}", | |||||
//"fileSizeLimitBytes": 524288000, | |||||
"rollingInterval": "Day", | |||||
"rollOnFileSizeLimit": "true", | |||||
"retainedFileCountLimit": 7 | |||||
} | |||||
} | |||||
], | |||||
"Filter": [ | |||||
{ | |||||
"Name": "ByIncludingOnly", | |||||
"Args": { | |||||
"Expression": "@l = 'Error'" | |||||
} | |||||
} | |||||
] | |||||
} | |||||
} | |||||
} | |||||
] | |||||
}, | |||||
//"Logging": { | |||||
// "LogLevel": { | |||||
// "Default": "Information", | |||||
// "Microsoft.AspNetCore": "Warning" | |||||
// } | |||||
//}, | |||||
"AllowedHosts": "*" | "AllowedHosts": "*" | ||||
} | } |