Introduction
Logging errors and information is crucial for maintaining and debugging applications. In this article, we'll explore how to enhance error logging using MySeriLogProject, a logging library designed to handle exceptions gracefully and improve the robustness of your applications. We'll discuss the importance of error handling, introduce MySeriLogProject, and demonstrate how to integrate it into your codebase effectively.
Why error logging matters
Error logging plays a vital role in software development for several reasons.
- Debugging: Logs provide valuable information for diagnosing and fixing bugs.
- Monitoring: Monitoring logs help detect issues and performance bottlenecks in real-time.
- Auditing: Logs serve as a record of application activity for compliance and auditing purposes.
- Improving User Experience: By capturing errors, developers can identify and address user-facing issues, improving overall user experience.
Introducing MySeriLogProject
MySeriLogProject is a logging library designed to simplify error logging and handling in .NET applications. It offers the following features.
- Graceful Error Handling: MySeriLogProject handles exceptions gracefully, preventing application crashes and ensuring uninterrupted operation.
- Flexible Configuration: Easily customize logging settings, including log levels, output formats, and destinations.
- Integration with .NET Ecosystem: Seamlessly integrates with popular .NET frameworks and libraries, such as ASP.NET Core and Entity Framework Core.
- Rich Logging Capabilities: Supports structured logging, enabling developers to log detailed information about exceptions and application events.
Integration guide
Follow these steps to integrate MySeriLogProject into your .NET application.
- Install MySeriLogProject Package: Add the MySeriLogProject NuGet package to your project using the following command.
dotnet add package MySeriLogProject
- Configure Logging: Configure MySeriLogProject in your application startup code, specifying logging settings such as log levels, output formats, and destinations. Here's an example configuration.
var logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console()
.WriteTo.File("log.txt", rollingInterval: RollingInterval.Day)
.CreateLogger();
Log.Logger = logger;
- Use Structured Logging: Utilize structured logging to log detailed information about exceptions and application events. For example.
try
{
// Code that may throw an exception
}
catch (Exception ex)
{
Log.Error(ex, "An error occurred: {ErrorMessage}", ex.Message);
}
- Handle Errors Gracefully: Wrap critical sections of your code in try-catch blocks to catch and log exceptions using MySeriLogProject. Ensure that exceptions are handled gracefully to prevent application crashes.
Example Code. Below is an example of integrating MySeriLogProject into a .NET application, demonstrating how to handle file system events and HTTP requests.
Interface Definition
namespace MySeriLogProject.CommanEntity.SeriLog
{
public interface ISeriLogger
{
bool PostSeriLog(string FileName);
bool WriteErrorLog(string className, string methodName, string ExceptionMessage, string ExceptionStackTrace);
bool WriteInformationLog(string className, string methodName, string InformationMessage);
void BackgroundThreadPostSeriLogOnAppStart();
}
}
Implementation
using MySeriLogProject.CommanEntity.Constant;
using MySeriLogProject.CommanEntity.Helper;
using Serilog;
using System;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Principal;
namespace MySeriLogProject.CommanEntity.SeriLog
{
public class SeriLogger : ISeriLogger
{
private readonly HttpClient _httpClient;
private ILogger logger;
public SeriLogger(HttpClient httpClient, ILogger logger)
{
_httpClient = httpClient;
this.logger = logger;
FileSystemWatcher logFileWatcher = new FileSystemWatcher(Constant.LocationProperties.LogFolderPath);
logFileWatcher.Created += OnFileCreated;
logFileWatcher.EnableRaisingEvents = true;
FileSystemWatcher ArchiveFileWatcher = new FileSystemWatcher(Constant.LocationProperties.DestinationFile);
ArchiveFileWatcher.Created += OnAcriveFileCreated;
ArchiveFileWatcher.EnableRaisingEvents = true;
}
private void OnFileCreated(object sender, FileSystemEventArgs e)
{
try
{
string folderPath = Constant.LocationProperties.LogFolderPath;
string archiveFolderPath = LocationProperties.DestinationFile;
string fileName = Path.GetFileName(e.FullPath);
// Get a list of all files in the folder
string[] files = Directory.GetFiles(folderPath);
foreach (string file in files)
{
string currentFileName = Path.GetFileName(file);
if (currentFileName != fileName)
{
string destinationPath = Path.Combine(archiveFolderPath, currentFileName);
File.Move(file, destinationPath);
}
}
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred while handling file creation: {ex.Message}");
}
}
private void OnAcriveFileCreated(object sender, FileSystemEventArgs e)
{
try
{
PushLogToSource(Directory.GetFiles(LocationProperties.DestinationFile));
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred while handling archive file creation: {ex.Message}");
}
}
public bool WriteErrorLog(string className, string methodName, string ExceptionMessage, string ExceptionStackTrace)
{
if (Directory.Exists(Constant.LocationProperties.LogFolderPath))
{
DependencyInjector.ls.MinimumLevel = Serilog.Events.LogEventLevel.Error;
logger.Error($"Class Name: {className}, Method Name: {methodName}, Error Msg: {ExceptionMessage}, Error StackTrace: {ExceptionStackTrace}, Version: {BuildVersion.BuildVersionNumber} ");
int? ExceptionCount = Convert.ToInt32(System.Environment.GetEnvironmentVariable("ExceptionCount", EnvironmentVariableTarget.User));
System.Environment.SetEnvironmentVariable("ExceptionCount", ExceptionCount == null ? "0" : (ExceptionCount + 1).ToString(), EnvironmentVariableTarget.User);
}
return false;
}
public bool WriteInformationLog(string className, string methodName, string InformationMessage)
{
if (Directory.Exists(Constant.LocationProperties.LogFolderPath))
{
DependencyInjector.ls.MinimumLevel = Serilog.Events.LogEventLevel.Information;
logger.Information($"Class Name: {className}, Method Name: {methodName}, Info Msg: {InformationMessage}, Version: {BuildVersion.BuildVersionNumber} ");
}
return false;
}
private Exception LogAndThrowHttpException(string apiUrl, string jsonResultString, HttpRequestException exception)
{
var result = ExceptionBuilder.GetErrorMessage(jsonResultString, exception);
return result.RequestException;
}
public void BackgroundThreadPostSeriLogOnAppStart()
{
string DestinationFilePath = LocationProperties.DestinationFile;
string[] destinationFilePaths = Directory.GetFiles(DestinationFilePath);
string sourceFolder = LocationProperties.LogFolderPath;
string[] sourceFilePaths = Directory.GetFiles(sourceFolder);
CleanArchive(destinationFilePaths);
MoveLogFileIntoArchive(sourceFilePaths);
}
private void MoveLogFileIntoArchive(string[] sourceFilePaths)
{
foreach (string filePath in sourceFilePaths)
{
try
{
string fileName = Path.GetFileName(filePath);
string destinationFilePath = Path.Combine(LocationProperties.DestinationFile, fileName);
if (File.Exists(filePath))
{
File.Move(filePath, destinationFilePath);
}
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred while moving log file into archive: {ex.Message}");
}
}
}
private void PushLogToSource(string[] sourceFilePaths)
{
foreach (string filePath in sourceFilePaths)
{
try
{
string fileName = Path.GetFileName(filePath);
string destinationFilePath = Path.Combine(LocationProperties.DestinationFile, fileName);
if (PostSeriLog(destinationFilePath))
{
File.Delete(destinationFilePath);
}
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred while pushing log to source: {ex.Message}");
}
}
}
private static void CleanArchive(string[] destinationFilePaths)
{
foreach (string destinationfilePath in destinationFilePaths)
{
try
{
if (File.Exists(destinationfilePath))
{
File.Delete(destinationfilePath);
}
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred while cleaning archive: {ex.Message}");
}
}
}
public bool PostSeriLog(string FileName)
{
bool result = false;
var jsonResultString = string.Empty;
var apiUrl = string.Empty;
try
{
apiUrl = Constant.ServiceUrls.D2DApiBaseURL + Constant.ServiceUrls.LogAPIPath;
var requestMessage = new HttpRequestMessage(HttpMethod.Post, apiUrl);
requestMessage.Headers.Add("ContentType", "text/plain");
var formContent = new MultipartFormDataContent
{
{ CreateValueContent("desktopID", System.Net.Dns.GetHostName() + "_" + WindowsIdentity.GetCurrent().Name.Replace("\\", ""))
},
{ CreateValueContent("UserID", Convert.ToString(CursorEvents.UserID))},
{ CreateValueContent("pairedMobileID", CursorEvents.pairedMobileID)},
{CreateFileContent(new FileInfo(FileName))},
};
var httpResponseMessage = _httpClient.PostAsync(apiUrl, formContent).Result;
jsonResultString = httpResponseMessage.Content.ReadAsStringAsync().Result;
if (httpResponseMessage.StatusCode == HttpStatusCode.OK)
{
jsonResultString = httpResponseMessage.Content.ReadAsStringAsync().Result;
httpResponseMessage.EnsureSuccessStatusCode();
result = true;
}
}
catch (HttpRequestException ex)
{
LogAndThrowHttpException(apiUrl, jsonResultString, ex);
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred while posting log: {ex.Message}");
}
return result;
}
private StreamContent CreateFileContent(FileInfo fileInfo)
{
var fileContent = new StreamContent(File.OpenRead(fileInfo.FullName));
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "\"logfile\"",
FileName = "\"" + fileInfo.Name + "\""
};
fileContent.Headers.ContentType = new MediaTypeHeaderValue("text/plain");
return fileContent;
}
private StringContent CreateValueContent(string Key, string Value)
{
var fileContent = new StringContent("\"" + Value + "\"");
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "\"" + Key + "\""
};
fileContent.Headers.Remove("Content-Type");
return fileContent;
}
}
}
Conclusion
MySeriLogProject simplifies error logging and handling in .NET applications, ensuring robustness and reliability. By integrating MySeriLogProject into your codebase and following best practices for error logging, you can effectively monitor, debug, and improve the quality of your applications.
References
😊Please consider liking and following me for more articles and if you find this content helpful.👍