• 集成Javascript Logging on MVC or Core


    ASP.NET Core provides us a rich Logging APIs which have a set of logger providers including: ConsoleLoggerPtoviderAzureAppServicesDiagnosticsLoggerProviderEventLogLoggerProvider and much more.

    This let C# developers happy than before, because you need to implement them loggers yourself in the past, however a lot of us writing JavaScript code in almost web applications which is little hard, but find the client-side exceptions & errors are even harder.

    There are many client-side loggers that you can name it, which are fit our needs, but today I wanna talk about the client-side logging from different angle. Me and you as developers suffer a lot from unexpected javascript error that happen occasionally, sometimes the reason is silly such missing a curly braces or broke a link .. etc.

    With that I was thinking last few days that it would be nice to integrate the client-side & server-side logs, so all the logs will be logged from the ASP.NET Core logger providers that we like and love instead of managing two different logger providers for both client-side & server-side.

    Logging JavaScript Events

    Basically the idea is very simple, I need to inject the client-side logging APIs script into our view, after that I need the JavaScriptLoggingMiddleware to listening to the upcoming script logs and forward them to ASP.NET Core logger providers.

    With that we're ready to show some code, but before that I need to mention that I didn't introduce a new logging APIs, but I could, so the javascript console object is enough for logging. In both cases we need to intercept the console logs as the following:

    (function () {
        var trace = console.trace;
        var debug = console.debug;
        var info = console.info;
        var warn = console.warn;
        var error = console.error;
    
        console.trace = function (message) {
            log(logLevel.Trace, message);
            trace.call(this, arguments);
        };
    
        console.debug = function (message) {
            log(logLevel.Debug, message);
            debug.call(this, arguments);
        };
    
        console.info = function (message) {
            log(logLevel.Information, message);
            info.call(this, arguments);
        };
    
        console.warn = function (message) {
            log(logLevel.Warning, message);
            warn.call(this, arguments);
        };
    
        console.error = function (message) {
            log(logLevel.Error, message);
            error.call(this, arguments);
        };
    })();
    

    The log is a method that I created to post the actual logs to the server, which will handled by the JavaScriptLoggingMiddleware that shown below.

    At this point I was wondering whether to store jsLogger script into the disk and render it using a tag helper or not!! after awhile I inspired by Application Insights and decided to store it into a resx file and retrieve them later using JavaScriptLoggingSnippet.

    public class JavaScriptLoggingMiddleware
    {
        private readonly ILogger _logger;
        private readonly RequestDelegate _next;
    
        public JavaScriptLoggingMiddleware(ILoggerFactory loggerFactory, RequestDelegate next)
        {
            _logger = loggerFactory.CreateLogger<JavaScriptLoggingMiddleware>();
            _next = next;
        }
    
        public async Task Invoke(HttpContext context)
        {
            if (context.Request.Path == "/log" && context.Request.Method == "POST" && context.Request.HasFormContentType)
            {
                var form = await context.Request.ReadFormAsync();
                var level = Convert.ToInt32(form["level"].First());
                var message = form["message"].First();
    
                switch ((LogLevel)level)
                {
                    case LogLevel.Trace:
                        _logger.LogTrace(message);
                        break;
                    case LogLevel.Debug:
                        _logger.LogDebug(message);
                        break;
                    case LogLevel.Information:
                        _logger.LogInformation(message);
                        break;
                    case LogLevel.Warning:
                        _logger.LogWarning(message);
                        break;
                    case LogLevel.Error:
                        _logger.LogError(message);
                        break;
                    default:
                        return;
                }
            }
            else
            {
                await _next(context);
            }
        }
    }
    

    If you look closely to the code above, you will notice that the middleware listening for specific url, when it hit I need to map the client-side log levels with the server-side once, after that I log them normally.

    I can finally log JavaScript Exceptions!

    Last but not least, sometimes we come up to a situation that we need to catch the global javascript exception that may occur for whatever reason could be. window.onerror is a good place to catch such exception.

    I added a JavaScriptLoggingOptions which is shown below to make things configurable in the way that you want.

    public class JavaScriptLoggingOptions
    {
        public bool HandleGlobalExceptions { get; set; }
    }

    By adding this simple property, the JavaScriptLoggingSnippet is now able to choose the proper script to render in the view.

    public class JavaScriptLoggingSnippet
    {
        private readonly JavaScriptLoggingOptions _loggingOptions;
    
        private static readonly HtmlString JavaScriptLoggingScript = new HtmlString(Resources.Script);
    
        private static readonly HtmlString JavaScriptLoggingGlobalExceptionHandlingScript = new HtmlString(Resources.GlobalExceptionHandlingScript);
    
        public JavaScriptLoggingSnippet(IOptions<JavaScriptLoggingOptions> loggingOptions)
        {
            _loggingOptions = loggingOptions.Value;
        }
    
        public HtmlString Script =>
            _loggingOptions.HandleGlobalExceptions ? FullScript : JavaScriptLoggingScript;
    
        private static HtmlString FullScript => JavaScriptLoggingScript.Concat(HtmlString.NewLine,
            JavaScriptLoggingGlobalExceptionHandlingScript);
    }

    What it takes to make everything happen?

    We need few steps to make this happen:

    First we need to configure the JavaScriptLogging service in the ConfigureServices method

    services.AddJavaScriptLogging(options =>
    {
        options.HandleGlobalExceptions = true;
    });

    After that adding the JavaScriptLoggingMiddleware to the Configure method

    app.UseJavaScriptLogging();

    Finally add the following line into your view or layout page to render the jsLogger script.

    @Html.Raw(JavaScriptLoggingSnippet.Script)

    You can download the source code for this post from my jsLogger repository on GitHub.

  • 相关阅读:
    无法添加sql server ER图
    我和COC
    WordPress怎样设置菜单栏旋转小图标
    VS Code怎样设置成中文
    初探 Git Submodules
    使用 rsync-deploy-action 同步 Hexo 博客到个人服务器
    Latex基本语法简记
    SQLAlchemy建立数据库模型之间的关系
    Flask的请求钩子与上下文简览
    如何将本地项目推送到Github
  • 原文地址:https://www.cnblogs.com/Javi/p/6473895.html
Copyright © 2020-2023  润新知