...
Após analise de como o log era gerado optou-se por modificar os logs, para que os mesmos sejam menos verbosos, mais assertivos e também contenham mais informação.
O APPSettings mudou para
| Bloco de código | ||||||
|---|---|---|---|---|---|---|
| ||||||
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning",
"Tnf": "Warning"
}
}, |
Podemos notar acima que apenas o default está como information enquanto os outros logs estão com warning, e incluimos o tnf também como warning isso tornou o log menos verboso.
No startup fizemos alterações conforme abaixo:
Seguindo o program alterações abaixo:
Alterações no log dentro do controller
| Bloco de código | ||||||
|---|---|---|---|---|---|---|
| ||||||
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using DocumentFormat.OpenXml.Office2010.Excel;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using PDVCore.Lib.Models.ViewModels;
using PDVSync.Core.Produto.Application.Services.Interfaces;
using PDVSync.Core.Produto.Dto.DadoDinamico;
using PDVSync.Core.Produto.Dto.Produto;
using PDVSync.Core.Produto.WebApi.V3.webConstants.pdvsyncclient;
using Serilog.Context;
namespace PDVSync.Core.Produto.WebApi.V3.Controllers.pdvsyncclient
{
[Route(WebConstants.ProdutoRouteName)]
[Route(WebConstants.ProdutoRouteNameVersion)]
[ApiController]
[ApiVersion("3.0")]
[Produces("application/json")]
[Consumes("application/json")]
public class ProdutoController : TnfController
{
private const string _name = "Produto";
private readonly ILogger<ProdutoController> _logger;
private readonly IDadoDinamicoAppService _dadoDinamicoAppService;
public ProdutoController(ILogger<ProdutoController> logger, IDadoDinamicoAppService dadoDinamicoAppService)
{
_logger = logger;
_dadoDinamicoAppService = dadoDinamicoAppService;
}
/// <summary>
/// Get Cliente
/// </summary>
/// <param name="idInquilino">Inquilino id do inquilino</param>
/// <param name="lote">Request params</param>
/// <param name="qtdRegistros">Request params</param>
/// <param name="sequencial">Request params</param>
/// <param name="listIdProprietario">Request params</param>
/// <returns>Cliente requested</returns>
[MapToApiVersion("3.0")]
[HttpGet("{idInquilino}/{lote}/{qtdRegistros}/{sequencial}")]
[ProducesResponseType(typeof(ResultViewModel<List<DadoDinamicoDto>>), 200)]
[ProducesResponseType(typeof(BadRequestObjectResult), 400)]
[TnfRoleAuthorize(ApiConstants.Authorizations.Profiles.PDVSync_Client)]
public async Task<IActionResult> GetAllAsync(string idInquilino,
string lote,
int qtdRegistros,
int sequencial,
[FromQuery] List<string> listIdProprietario)
{
using var apiVersionContext = LogContext.PushProperty("APIVersion", 3); // A adição de campos como esse geram dados no log que é enviado para o grafana!!!
using var inquilinoContext = LogContext.PushProperty("IdInquilino", idInquilino);
using var loteContext = LogContext.PushProperty("Lote", lote);
using var qtdRegistrosContext = LogContext.PushProperty("qtdRegistros", qtdRegistros);
using var sequencialContext = LogContext.PushProperty("sequencial", sequencial);
_logger.LogInformation($"Iniciando atualização do {_name}.");
var stopwatch = new Stopwatch();
try
{
if (string.IsNullOrEmpty(idInquilino) ||
string.IsNullOrEmpty(lote) ||
listIdProprietario != null && listIdProprietario.Count <= 0)
{
_logger.LogWarning(_name + " com ID {ProdutoId} não foi localizado.", idInquilino);
return BadRequest();
}
var listProdutoDto = await _dadoDinamicoAppService.GetListaBaixaAsync(12,
idInquilino,
lote,
qtdRegistros,
sequencial,
listIdProprietario);
stopwatch.Stop();
using var tempoTotalContext = LogContext.PushProperty("ElapsedMilliseconds", stopwatch.ElapsedMilliseconds);
if (listProdutoDto == null || listProdutoDto.Count <= 0)
{
using var registrosRetornadosContext = LogContext.PushProperty("RegistrosRetornados", 0);
return Ok(new ResultViewModel<List<DadoDinamicoDto>>()
{
Success = false,
Message = "Nenhum registro encontrado"
});
}
int registrosRetornados = listProdutoDto?.Count ?? 0;
var loteOrigem = listProdutoDto?.FirstOrDefault()?.LoteOrigem;
if (!string.IsNullOrEmpty(loteOrigem))
{
using var loteOrigemContext = LogContext.PushProperty("LoteOrigem", loteOrigem);
using var registrosRetornadosContext = LogContext.PushProperty("RegistrosRetornados", registrosRetornados);
}
_logger.LogInformation($"Busca de de {_name} finalizada com sucesso.");
return Ok(new ResultViewModel<List<DadoDinamicoDto>>()
{
Success = true,
Message = "",
Data = listProdutoDto.ToList(),
TotalTime = stopwatch.ElapsedMilliseconds,
NumberOfRecords = listProdutoDto.Count()
});
}
catch (Exception ex)
{
_logger.LogError("Erro ao buscar Produtos. | Método: "
+ System.Reflection.MethodBase.GetCurrentMethod().DeclaringType + "." + System.Reflection.MethodBase.GetCurrentMethod().Name
+ " | Erro: "
+ ex.Message);
return BadRequest("Erro ao buscar Produtos: " + ex.Message);
}
}
}
}
|
A adição de pushproperty no log context faz com que a informação seja colocada em uma coluna do log. Importante salientar que o information que vai após o log vai carregar todos os properties anteriores, portando os que são adicionados depois vão no proximo information ou error.
Importante que qualquer informação colocada no pushproperty tem que estar no schema que vou adicionar abaixo:
| Bloco de código | ||||||
|---|---|---|---|---|---|---|
| ||||||
[
{"name": "partition_time", "type": "TIMESTAMP"},
{"name": "Timestamp","type": "TIMESTAMP","mode": "NULLABLE","description": "Timestamp of the log entry."},
{"name": "Level","type": "STRING","mode": "NULLABLE","description": "Log level (e.g., Information, Error, Warning)."},
{"name": "MessageTemplate","type": "STRING","mode": "NULLABLE","description": "Template for the log message."},
{"name": "Exception","type": "STRING","mode": "NULLABLE","description": "Exception details, if any."},
{"name": "Properties","type": "RECORD","mode": "NULLABLE","fields": [
{"name": "SourceContext","type": "STRING","mode": "NULLABLE"},
{"name": "Application","type": "STRING","mode": "NULLABLE"},
{"name": "Area","type": "STRING","mode": "NULLABLE"},
{"name": "Enviroment","type": "STRING","mode": "NULLABLE"},
{"name": "Service","type": "STRING","mode": "NULLABLE"},
{"name": "Software","type": "STRING","mode": "NULLABLE"},
{"name": "CpuUsagePercent","type": "FLOAT","mode": "NULLABLE"},
{"name": "MemoryUsageMB","type": "FLOAT","mode": "NULLABLE"},
{"name": "MemoryUsagePercent","type": "FLOAT","mode": "NULLABLE"},
{"name": "ApplicationName","type": "STRING","mode": "NULLABLE"},
{"name": "RequestHost","type": "STRING","mode": "NULLABLE"},
{"name": "UserAgent","type": "STRING","mode": "REPEATED"},
{"name": "ClientIp","type": "STRING","mode": "NULLABLE"},
{"name": "RequestMethod","type": "STRING","mode": "NULLABLE"},
{"name": "RequestPath","type": "STRING","mode": "NULLABLE"},
{"name": "StatusCode","type": "INTEGER","mode": "NULLABLE"},
{"name": "Elapsed","type": "FLOAT","mode": "NULLABLE"},
{"name": "RequestId","type": "STRING","mode": "NULLABLE"},
{"name": "ConnectionId","type": "STRING","mode": "NULLABLE"},
{"name": "AuthenticationScheme","type": "STRING","mode": "NULLABLE"},
{"name": "FailureMessage","type": "STRING","mode": "NULLABLE"},
{"name": "EventId","type": "RECORD","mode": "NULLABLE","fields":[
{"name": "Id","type": "INTEGER","mode": "NULLABLE"},
{"name": "Name","type": "STRING","mode": "NULLABLE"}]},
{"name": "ActionId","type": "STRING","mode": "NULLABLE"},
{"name": "ActionName","type": "STRING","mode": "NULLABLE"},
{"name": "RegistrosRecebidos","type": "INTEGER","mode": "NULLABLE"},
{"name": "LoteOrigem","type": "STRING","mode": "NULLABLE"},
{"name": "IdInquilino","type": "STRING","mode": "NULLABLE"},
{"name": "APIVersion","type": "INTEGER","mode": "NULLABLE"},
{"name": "RegistrosCount","type": "INTEGER","mode": "NULLABLE"},
{"name": "Elapsedms","type": "FLOAT","mode": "NULLABLE"},
{"name": "ElapsedMilliseconds","type": "INTEGER","mode": "NULLABLE"},
{"name": "RegistrosProcessados","type": "INTEGER","mode": "NULLABLE"},
{"name": "Inquilino","type": "STRING","mode": "NULLABLE"},
{"name": "RegistrosRetornados","type": "INTEGER","mode": "NULLABLE"},
{"name": "Lote","type": "STRING","mode": "NULLABLE"},
{"name": "sequencial","type": "INTEGER","mode": "NULLABLE"},
{"name": "qtdRegistros","type": "INTEGER","mode": "NULLABLE"},
{"name": "DataBusca","type": "STRING","mode": "NULLABLE"}
]},
{"name": "Renderings","type": "RECORD","mode": "NULLABLE","fields": [
{"name": "Elapsed","type": "RECORD","mode": "REPEATED","fields": [
{"name": "Format","type": "STRING","mode": "NULLABLE"},
{"name": "Rendering","type": "STRING","mode": "NULLABLE"}
]},
{"name": "Elapsedms","type": "RECORD","mode": "REPEATED","fields": [
{"name": "Format","type": "STRING","mode": "NULLABLE"},
{"name": "Rendering","type": "STRING","mode": "NULLABLE"}
]}
]}
]
|
Importante colocar os pushProperties, principalmente com as informações relevantes que existirem no momento, como por exemplo inquilino, lote origem, lote registros recebidos, registros processados e registros retornados.