Error notification: from each circuit in its own way

    Conceptually


    Goal briefly


    It is necessary to achieve prompt (instant) notification of responsible people about errors in all application instances. Moreover, for different instances there must be different ways of delivering logs: for local launch by the programmer, notify him only; from PROD - lead of the project, immediately mobilizing them; from the test server - responsible for the corresponding circuit.


    In detail


    Using NLog will allow you to configure the method of delivering logs not in the application code (in the C # code there will be _logger.Info (message) or _logger.Error (exception) ), but in the xml configuration file NLog.config . At the level of this file for different levels (and other necessary conditions) it is possible to set different delivery methods. There are four main methods:


    • in the database - the sql command is called with the parameters specified by the config;
    • to the file — a line formed in the specified format is added to the specified file (changing files is possible — for example, if the file name is specified by the date, then a new file will be added every day; the use of variables is possible);
    • by email - a letter is generated, formed according to a given template;
    • to the console - relevant only for console applications, the output line is also formed according to the template specified by the config.

    There are other ways, including you can create your own way by attaching it to the application with a plugin.


    For quick delivery of errors (exceptions) in a web application, they are best delivered by email . All other (information) logs can be saved either in the database or in a file . And in case of launching the console application - everything is in the console . Thus, when executing the same C # code (C # libraries), the logs must be delivered in different ways - this is achieved by highlighting the delivery conditions in a separate file, NLog.config , which is stored in the project of the launched application.


    The same logging record can be delivered in several ways at the same time - for example, errors other than sending by email should be saved in the main log storage.


    To have different settings for log delivery for different loops (application instances), you need to use config transformations . It is necessary to do so, and with their help it is possible to:


    • when running locally (by a programmer on his computer), error messages were sent only to him (and so for each developer!), information logs were written to the local database;
    • when launched on PROD, letters were sent by another smtp server to a specific distribution group, and information logs were written to the production log repository;
    • when launched on the test server, letters were sent by the internal smtp server, and information logs were sent to the test log storage.

    For this, C # sources do not need to be edited - it is enough to have different NLog.config files in different running projects and config transformations on these files.


    How to do it


    All this is possible by taking the logging settings to the config file (which gives us NLog), and configuring config transformations on it.


    Nlog.config


    I defined target 's:


    databaseLog

    mailtargetError

    Console

    Delivery rules ( rules ) in NLog.config for web applications look like this:



    Such a record means that errors will be sent by email and written to the database, and all logs below the level will only be written to the database.


    The delivery rule for the console looks like this:



    It means outputting all logs to the console.


    So that you can redefine the parameters in config transformations separately, you can put out nlog variables:



    Log additional data


    NLog allows you to display, in addition to this information line or exception, a lot of data (see the documentation ). If you need to save special data, this is possible using event-properties :


    LogEventInfo e = new LogEventInfo(LogLevel.Info, _logger.Name, "message");
    e.Properties["userId"] = user.Id;
    _logger.Log(e);

    Then in NLog.config you can use the variable $ {event-properties: item = domainId} :


    
        ...

    Config transformations


    1) Config transformation 's are possible only on solution configuration . Therefore, it is needed for each circuit (instance of the application) its own, including for each developer - its own. Example personal solution configuration :




    2) Select it as active:



    3) Next, you need to install the Visual Studio extension " Configuration Transform " ( https://marketplace.visualstudio.com/items?itemName=GolanAvraham.ConfigurationTransform ).

    After installation, for any file (!) In Solution Explorer, the items " Add Config Transforms ", " Preview Config Transforms " appear :




    4) The item " Add Config Transforms " means adding a file of the form " name.configuration name.extension " for each project configuration of this file (not a solution!), And including (nest) them under the file - they are already added to the screenshot.

    This adds the necessary tags to the project file (.csproj).

    An example is App.config , NLog.config :


    $(TargetFileName).config$(_DeploymentApplicationDir)$(TargetName)$(TargetExt).config$(_DeploymentFileMappingExtension)

    (TeamCity picks up these transformations because they are part of the build process)


    With this spelling of tags, the original file ( Web.config , NLog.config ) does not change , only the resulting file is edited, which is placed in the assembly folder - this means that it will not be constantly changed and commited every time if the developers have a personal solution configuration there will be various transformations of this file.


    5 Next, in the created NLog.username.config file corresponding to the personal solution configuration , you need to replace the address of the error recipient:



    And for the production loop (for example):



    Help on writing transformations


    A comprehensive help on writing transformations here: https://msdn.microsoft.com/en-us/library/dd465326(v=vs.110).aspx


    Кратко:
    Чтобы заменить целый тег, нужно его пометить атрибутом xdt:Transform="Replace":



    Чтобы удалить целый тег, нужно его пометить атрибутом xdt:Transform="Remove":



    Чтобы вставить тег, нужно его пометить атрибутом xdt:Transform="Insert":



    Чтобы добавить атрибуты тега, нужно его пометить атрибутом xdt:Transform="SetAttributes(список атрибутов через зпт)", добавляя и сами атрибуты:



    Чтобы удалить атрибут тега, нужно его пометить атрибутом xdt:Transform="RemoveAttributes(список атрибутов через зпт)":



    To replace attribute values, you need to tag the attributes xdt: Locator = "Match (name)" xdt: Transform = "SetAttributes" :



    Result


    When a developer starts a web project from Visual Studio, error messages will be sent only to the launching developer (if he does everything described above), when launched from the console - only to him in the console, when launched on the PROD - as indicated in NLog.Prod .config .


    Example


    Global.asax.cs :


    static readonly Logger _logger = LogManager.GetLogger("Global.asax");
    protected void Application_Error(object sender, EventArgs e)
    {
        HttpApplication app = (HttpApplication)sender;
        Exception ex = Server.GetLastError();
        _logger.Fatal(ex, $"Application_Error: {app.Context.Request.RawUrl}");
    }

    WebAPI controller:


    // поле класса:
    static readonly Logger _logger = LogManager.GetLogger("(имя класса)");
    // в методах:
    try
    {
       // code
    }
    catch (SomeSoftException ex)
    {
        return BadRequest(ex.Message);
    }
    catch (Exception ex)
    {
        _logger.Error(ex); // послать email и записать в лог
        return base.InternalServerError(ex);
    } 

    Also popular now: