Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ttpullima/RomsoftBackEnd2021_v2/llms.txt

Use this file to discover all available pages before exploring further.

The Gestión Clínica API employs two complementary logging mechanisms that serve distinct purposes. The first is log4net, which captures unexpected exceptions and infrastructure errors to a rolling text file on the server filesystem. The second is a database audit log powered by LogBL, which records every intentional user action — patient registration, insurance plan update, login — as a structured row in the database, giving clinic administrators a permanent, queryable trail of who did what and when.

Mechanism 1 — log4net Exception Logging

Configuration in Web.config

log4net is configured entirely within Web.config using a dedicated <log4net> section. The section handler is declared in <configSections> at the top of the file:
<configSections>
  <section
    name="log4net"
    type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
The log4net section itself defines two appenders and a root logger:
<log4net>

  <!-- Writes to the Visual Studio Output / Debug console -->
  <appender name="DebugAppender" type="log4net.Appender.DebugAppender">
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date %-5level %logger - %message%newline" />
    </layout>
  </appender>

  <!-- Writes to Log/Log.txt with size-based rolling -->
  <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
    <file value="Log/Log.txt" />
    <appendToFile value="true" />
    <rollingStyle value="Size" />
    <maxSizeRollBackups value="10" />
    <maximumFileSize value="1MB" />
    <staticLogFileName value="true" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date %-5level %logger - %message%newline" />
    </layout>
  </appender>

  <!-- Root logger: capture everything (ALL level), send to both appenders -->
  <root>
    <level value="All" />
    <appender-ref ref="DebugAppender" />
    <appender-ref ref="RollingFileAppender" />
  </root>

</log4net>

Rolling File Appender Settings

SettingValueMeaning
fileLog/Log.txtPath relative to the IIS application root
appendToFiletrueNew entries are appended, not overwriting the file
rollingStyleSizeRoll files when size limit is reached
maxSizeRollBackups10Keep up to 10 backup files (Log.txt.1Log.txt.10)
maximumFileSize1MBRoll to a new backup when current file exceeds 1 MB
staticLogFileNametrueActive log always named Log.txt; backups get numeric suffixes

Pattern Layout

Each log entry uses the pattern %date %-5level %logger - %message%newline, which produces lines such as:
2024-03-15 09:42:17,334 ERROR  - Mensaje: Object reference not set Trace: at Romsoft…
TokenOutput
%dateFull timestamp including milliseconds
%-5levelLog level left-padded to 5 characters (ERROR, WARN , INFO )
%loggerLogger name (empty string for the root logger)
%messageThe formatted message
%newlinePlatform-appropriate line terminator

Bootstrapping log4net

log4net is initialized once in Global.asax.cs during Application_Start:
protected void Application_Start()
{
    GlobalConfiguration.Configure(WebApiConfig.Register);
    log4net.Config.XmlConfigurator.Configure(); // reads <log4net> from Web.config
    AutoMapperConfiguration.Configure();
}

Using the Logger in Controllers

BaseController exposes a shared root logger as a protected static field:
public class BaseController : ApiController
{
    protected static readonly ILog Logger =
        LogManager.GetLogger(string.Empty); // binds to root logger

    protected void LogError(Exception exception)
    {
        Logger.Error(string.Format(
            "Mensaje: {0} Trace: {1}",
            exception.Message,
            exception.StackTrace));
    }

    protected void LogError(string mensaje)
    {
        Logger.Error(mensaje);
    }
}
Every controller action wraps its body in a try/catch and calls LogError(ex) in the catch block. This ensures that no exception is silently swallowed — it always lands in Log/Log.txt alongside a JsonResponse with Success=false.

Mechanism 2 — Database Audit Log

The Log Entity

The Log class in Romsoft.GESTIONCLINICA.Entidades defines the schema of the audit record:
public class Log
{
    public int      Id              { get; set; }
    public string   DireccionIP     { get; set; }  // Client IP address
    public string   Usuario         { get; set; }  // Username performing the action
    public string   Mensaje         { get; set; }  // Outcome message
    public string   Controlador     { get; set; }  // Controller name (e.g. "Usuario")
    public string   Accion          { get; set; }  // Action name (e.g. "Add", "Update")
    public DateTime FechaRegistro   { get; set; }  // Timestamp (set by DB default)
    public string   Objeto          { get; set; }  // JSON-serialized request DTO
    public int?     Identificador   { get; set; }  // ID of the affected record (nullable)
}

Audit Log Fields

FieldTypeDescription
IdintAuto-increment primary key
DireccionIPstringIP address of the calling client
UsuariostringUsername from the DTO (e.g., pacienteDTO.UsuarioCreacion)
MensajestringThe JsonResponse.Message returned to the client
ControladorstringModule identifier string from Mensajes (e.g., "Usuario")
AccionstringOperation name: "Add", "Update", "Delete", "Login"
FechaRegistroDateTimeTimestamp of the action, typically set by a SQL DEFAULT GETDATE()
ObjetostringFull JSON serialization of the DTO that was sent (via JsonConvert.SerializeObject)
Identificadorint?Primary key of the affected row (0 for inserts before the ID is known)

Writing an Audit Record

The LogBL singleton provides a single Add method:
public class LogBL : Singleton<LogBL>, ILogBL<Log>
{
    public int Add(Log entity)
    {
        return LogRepository.Instancia.Add(entity);
    }
}
Controllers call LogBL.Instancia.Add(new Log { … }) inside the try block, after the primary business operation completes, so that the audit record captures the real outcome — including any warning message:
[HttpPost]
public JsonResponse Add(ADM_PACIENTEDTO pacienteDTO)
{
    var jsonResponse = new JsonResponse { Success = true };
    try
    {
        var paciente = MapperHelper.Map<ADM_PACIENTEDTO, ADM_PACIENTE>(pacienteDTO);
        // … business logic …

        // Audit record written regardless of Success/Warning outcome
        LogBL.Instancia.Add(new Log
        {
            Accion       = Mensajes.Add,                          // "Add"
            Controlador  = Mensajes.UsuarioController,            // "Usuario"
            Identificador = 0,
            Mensaje      = jsonResponse.Message,
            Usuario      = pacienteDTO.UsuarioCreacion,
            Objeto       = JsonConvert.SerializeObject(pacienteDTO)
        });
    }
    catch (Exception ex)
    {
        LogError(ex);                          // log4net — stack trace to file
        jsonResponse.Success = false;
        jsonResponse.Message = Mensajes.IntenteloMasTarde;
    }
    return jsonResponse;
}
Every Add, Update, Delete, and Login operation writes an audit record to the database, even when the operation returns a business warning (e.g., duplicate record). This means the audit table captures all attempts, not just successful ones. Exception failures are recorded by log4net only (to Log/Log.txt), since the LogBL.Instancia.Add call is inside the try block and would not execute if the exception occurs before it.

Action Name Constants

The Mensajes class defines string constants used for the Accion field:
public static string Add             = "Add";
public static string Update          = "Update";
public static string Delete          = "Delete";
public static string Login           = "Login";
public static string AddDetalleGrupal = "AddDetalleGrupal";

Comparing the Two Mechanisms

Aspectlog4net (Log/Log.txt)Database Audit Log
Triggered byUnhandled exceptions in catch blockEvery CRUD/Login action in try block
StorageRolling text file on IIS serverLog table in SQL Server
QueryableNo (text file)Yes (SQL SELECT)
Contains stack traceYesNo
Contains request payloadNoYes (JSON-serialized DTO)
Survives server restartYes (persistent file)Yes (persistent database)
PurposeDeveloper/ops incident investigationClinical compliance and audit trail
Set up a scheduled job or SQL Agent task to archive or purge rows from the Log audit table older than a compliance-defined retention period (e.g., 5 years for Peruvian clinical records). The FechaRegistro column is the natural partition key for this archival process.

Build docs developers (and LLMs) love