Skip to content

ChangeLog

catalin.gavan edited this page Jul 5, 2019 · 10 revisions

KissLog 3.4.0

Release date: 05-07-2019

Improvements

Implemented logger.AddCustomProperty(key, value) method.

Custom properties can be viewed from the RequestLog view, and they can be accessed from within the Alerts JavaScript context.

Usage

[HttpPost]
public IActionResult CompleteCheckout(CheckoutViewModel model)
{
    ILogger logger = Logger.Factory.Get();

    logger.AddCustomProperty("IsHighPriority", true);
    logger.AddCustomProperty("BillingValue", 1320.04);
    logger.AddCustomProperty("Customer", "Ante Manufacturing Com");
}

Custom properties

Breaking changes

For .NET MVC and .NET WebApi applications, Application_Error method needs to be updated to ensure that KissLog logs startup exceptions.

This is achieved by using the Logger.NotifyListeners(logger) method.

New usage:

protected void Application_Error(object sender, EventArgs e)
{
    Exception exception = Server.GetLastError();
    if (exception != null)
    {
        var logger = Logger.Factory.Get();
        logger.Error(exception);

        if(logger.AutoFlush() == false)
        {
            Logger.NotifyListeners(logger);
        }
    }
}

KissLog 3.3.0

Implemented logging integration for Windows / Console applications.

Usage

namespace ConsoleApp_sample
{
    class Program
    {
        static void Main(string[] args)
        {
            ILogger logger = new Logger(url: "Main");

            try
            {
                logger.Debug("Hello world from Console application!");
            }
            catch (Exception ex)
            {
                logger.Error(ex);
                throw;
            }
            finally
            {
                Logger.NotifyListeners(logger);
            }
        }
    }
}

Console app logs

KissLog.AspNetCore 2.2.1

Release date: 21-05-2019

Implemented app.UseKissLogMiddleware(options) overload.

Usage

public class Startup
{
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseStaticFiles();

        app.UseKissLogMiddleware(options => {
            options.Listeners.Add(new KissLogApiListener(new KissLog.Apis.v1.Auth.Application(
                Configuration["KissLog.OrganizationId"],
                Configuration["KissLog.ApplicationId"])
            ));

            options.Options.ShouldLogResponseBody((logListener, logArgs, defaultValue) => {
                return logArgs.WebRequestProperties.Response.HttpStatusCode >= System.Net.HttpStatusCode.BadRequest;
            });
        });

        app.UseMvc();
    }
}

KissLog 3.2.0

Release date: 19-05-2019

Breaking changes

Environment configuration has been removed.

Old usage:

KissLogConfiguration.Listeners.Add(new KissLogApiListener(
    Configuration["KissLog.OrganizationId"],
    Configuration["KissLog.ApplicationId"],
    Configuration["KissLog.Environment"]
));

New usage:

KissLogConfiguration.Listeners.Add(new KissLogApiListener(new KissLog.Apis.v1.Auth.Application(
    Configuration["KissLog.OrganizationId"],
    Configuration["KissLog.ApplicationId"])
));

Options

New methods and properties:

public class Options
{
    // runtime handler used add search keywords for a request
    AddRequestKeywords(Func<FlushLogArgs, IEnumerable<string>> handler) => null;
}

Usage:

void Application_Start()
{
    KissLogConfiguration.Options
        .AddRequestKeywords((FlushLogArgs args) =>
        {
            if ((int)args.WebRequestProperties.Response.HttpStatusCode >= 400)
            {
                if(args.WebRequestProperties.Url.LocalPath.Contains("/checkout/process"))
                {
                    // find "/checkout/process" unsuccessful Request
                    // by searching for "checkoutFailed" keyword
                    return new[] { "checkoutFailed" };
                }
            }

            return null;
        });
}

General improvements and fixes

Creating multiple log categories would not work in some scenarios. This issue has been fixed.

public void Foo(string sqlScript)
{
    Logger.Factory.Get().Debug("Foo started");

    Logger.Factory.Get("EntityFramework").Debug(new Args("ExecuteSqlCommand script", sqlScript));

    _db.Database.ExecuteSqlCommand(new RawSqlString(sqlScript));

    Logger.Factory.Get().Debug("Foo completed");

    return View();
}

KissLogApiListener has been improved.

KissLog 3.1.1

Release date: 27-03-2019

Options

New methods and properties:

public class Options
{
    // runtime handler used to include / exclude ResponseBody
    ShouldLogResponseBody(Func<ILogListener, FlushLogArgs, bool, bool> handler) => defaultValue;
}

Usage:

void Application_Start()
{
    KissLogConfiguration.Options
        .ShouldLogResponseBody((ILogListener listener, FlushLogArgs args, bool defaultValue) =>
        {
            if ((int) args.WebRequestProperties.Response.HttpStatusCode >= 400)
            {
                // explicitly log the ResponseBody if the HTTP request was unsuccessful
                return true;
            }

            // use the defaultValue (which is calculated based on the Response Content-Type header)
            return defaultValue;
        });
}

KissLog 3.1.0

Release date: 26-03-2019

Starting with this version, Response.ContentLength will be automatically logged for all the HTTP requests.

KissLog 3.0.0

Release date: 15-03-2019

Logger

New methods and properties:

public static class Logger
{
    // creates FlushLogArgs for a given ILogger instance
    FlushLogArgs CreateFlushArgs(ILogger logger)
}

Usage:

public void Foo()
{
    ILogger logger = Logger.Factory.Get();
    FlushLogArgs args = Logger.CreateFlushArgs(logger);

    Console.WriteLine(args.MessagesGroups.Count());
}

KissLogConfiguration

Removed methods and properties:

public static class KissLogConfiguration
{
    // -> moved to Options.GetUser
    Func<RequestProperties, string> GetLoggedInUserName { get; set; }
    Func<RequestProperties, string> GetLoggedInUserEmailAddress { get; set; }
    Func<RequestProperties, string> GetLoggedInUserAvatar { get; set; }

    // -> moved to Options.ShouldLogRequestInputStream
    Func<WebRequestProperties, bool> ShouldLogRequestInputStream { get; set; }

    // -> moved to Options.ShouldLogRequestCookie
    Func<string, bool> ShouldLogCookie = { get; set; }

    // -> moved to Options.AppendExceptionDetails
    Func<Exception, string> AppendExceptionDetails { get; set; }

    // removed
    Func<WebRequestProperties, bool> ShouldLogResponseBody { get; set; }
}

New methods and properties:

public static class KissLogConfiguration
{
    // holds all the KissLog configuration
    Options Options { get; }
}

LogListenerParser

Removed methods and properties:

public class LogListenerParser
{
    // removed
    List<string> KeysToObfuscate { get; set; }

    // removed
    virtual bool ShouldLog(WebRequestProperties webRequestProperties, ILogListener logListener)

    // -> moved to BeforeFlush(FlushLogArgs args, ILogListener logListener)
    virtual void AlterDataBeforePersisting(FlushLogArgs args)

    // -> moved to BeforeFlush(FlushLogArgs args, ILogListener logListener)
    virtual void RemoveDataBeforePersisting(FlushLogArgs args)
}

New methods and properties:

public class LogListenerParser
{
    // callback which is called automatically before persisting the logs. FlushLogArgs can be altered at this step
    virtual void BeforeFlush(FlushLogArgs args, ILogListener logListener)
}

Options

Container for KissLog configuration.

public class Options
{
    // JSON settings used when serializing the object arguments on log message
    JsonSerializerSettings JsonSerializerSettings { get; }

    // handler to populate the logged-in user properties (used for https://kisslog.net user interface)
    GetUser(Func<RequestProperties, UserDetails> handler)

    // runtime handlers used to include / exclude different HTTP properties
    ShouldLogRequestHeader(Func<ILogListener, FlushLogArgs, string, bool> handler) => true;
    ShouldLogRequestCookie(Func<ILogListener, FlushLogArgs, string, bool> handler) => false;
    ShouldLogRequestQueryString(Func<ILogListener, FlushLogArgs, string, bool> handler) => true;
    ShouldLogRequestFormData(Func<ILogListener, FlushLogArgs, string, bool> handler) => true;
    ShouldLogRequestServerVariable(Func<ILogListener, FlushLogArgs, string, bool> handler) => true;
    ShouldLogRequestClaim(Func<ILogListener, FlushLogArgs, string, bool> handler) => true;
    ShouldLogRequestInputStream(Func<ILogListener, FlushLogArgs, bool> handler) => true;
    ShouldLogResponseHeader(Func<ILogListener, FlushLogArgs, string, bool> handler) => true;

    // runtime handler used to toggle a specific LogListener
    ToggleListener(Func<ILogListener, FlushLogArgs, bool> handler) => true;

    // runtime handler used to append custom text when an Exception is encountered
    AppendExceptionDetails(Func<Exception, string> handler) => null;
}

Usage:

void Application_Start()
{
    // update JSON settings
    KissLogConfiguration.Options
        .JsonSerializerSettings.Converters.Add(new StringEnumConverter());

    // prevent CardNumber parameter from being logged
    KissLogConfiguration.Options
        .ShouldLogRequestFormData((ILogListener listener, FlushLogArgs args, string name) =>
        {
            if (name == "CardNumber")
                return false;

            return true;
        });

    // append EntityFramework validation exceptions to the log messages
    KissLogConfiguration.Options
        .AppendExceptionDetails((Exception ex) =>
        {
            if (ex is DbEntityValidationException dbException)
            {
                StringBuilder sb = new StringBuilder();

                foreach (var validationErrors in dbException.EntityValidationErrors)
                {
                    foreach (var validationError in validationErrors.ValidationErrors)
                    {
                        sb.AppendLine(string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage));
                    }
                }

                return sb.ToString();
            }

            return null;
        });
}
You can’t perform that action at this time.