Peek inside Umbraco V8+ NuCache files with the NuCache Explorer tool

Hello again!
Let’s jump straight into the guts of this post and talk about NuCache and Umbraco V8+

What is NuCache

Well that is a harder topic for me to explain and is probably best explained by the creator himself, Stephan.
Fast forward to 22m:47s to learn all about NuCache

What is NuCache Explorer?

It’s a small desktop application that I have built to help you explore and view documents inside NuCache with a JSON representation of what is stored for a document in the NuCache.

I saw a need for this because unlike previous versions of Umbraco the cache of the website was stored in an XML file that could be opened in a simple text editor, with NuCache the files are generated with a dictionary package that saves binary files to disk. So trying to open a NuCache file in a text editor would not allow you to see what is inside your website cache.
I wanted a way to see and confirm what values are being published to variants so hence the need for this tool was born.

Features

OK so here is a quick lowdown of features:

  • Drag and Drop to open NuCache files
  • Native Windows file association to NuCache .db files
  • View document as JSON
  • Save/export all documents to JSON
  • Find/goto document by its integer ID or unique guid
  • Goto line, find, find next and find previous in JSON document
  • Recent document support via Windows taskbar
  • Set your own theme for the JSON viewer

Where do I download it?

Go jump on over to GitHub and visit the releases page where you can download the 1.1.0 installer.exe which will get you all setup and ready to start inspecting V8 NuCache files if you are experimenting with V8 or have been attending the V8 hackathons.

Thanks

A couple of thanks. One to Stephan for creating NuCache and lending me some of his code from a command line tool which powers this application in a more UI friendly way. So kudos Stephan!

Next thanks is to another fellow HQ colleage, this time Rune in giving me some pointers, ideas and making the UI hella-lot better to look at, so thanks Rune!

Next time…

For the next blog post, I plan to try and talk about how this little utility app works and how maybe you can start making your own tools too, so watch this space shortly…

For the curious hackers and impatient people, I am sure you can jump over to the GitHub repository and look through the source code to see how it was built.

Advertisements

Umbraco V8 – Swapping Log4Net for Serilog with this switcheroo magic trick

So in this blog post I will perform a switcheroo trick and swap the logging framework used in Umbraco V8 from Log4Net to use Serilog, however I will be one of those awful magicians from that crumby late 90’s show that revealed magician’s secrets to tricks.

That 90’s show where the magician would show how tricks were done

But first up let me try and tell you why I even decided to try and do this in the first place…

Why bother doing a switcheroo with logging frameworks?

I will try my best to explain why I wanted to switch out the current default Logging Framework used for Umbraco which is Log4Net for a Logging Framework called Serilog.

Serilog is a Logging framework that enables structured logging, which is a way to provide more additional meta information to your log with properties versus Log4Net’s approach which simply logs out the given string to a text file or other endpoint.

The main benefit that I see with structured logging, it allows you to query and find log items a lot easier than trawling through an arbitrary text log file, looking for clues and how log items may or may not relate to one another.

For example you could find all Log messages from a given class/type very quickly, find a group of related log items for member id 1234 and perhaps even add the environment in which the log came from such as Development, Staging or Live. Having this extra metadata of properties to search & filter on gives you some great tools & insights into looking through logs in a more organised fashion.

If you use Serilog’s Sinks, a term which is a datastore for logs, then you are able to output the logs to several places at once such as traditional text files, databases or perhaps more useful tools like ElasticSearch or even Serilog’s author companion tool Seq which allows you to visually, perform complex searches & queries to get an insight into your logs.

A screenshot from Seq, a tool to visually filter & query logs

I think I may have done a terrible job of trying to explain this in a short summary, but least I tried ¯\_(ツ)_/¯

Find my explanation a little lacking?!

Then you can watch the creator Nicholas Blumhardt talk about structured logging, Serilog & Seq from his 2017 NDC talk explain it much better than I can.

OK enough why, just show me how to do the magic

So in Umbraco V8 you can create a new class that inherits from the class Umbraco.Web.UmbracoApplication, in doing so you are then able to override the method called GetLogger to return an implementation of Umbraco’s ILogger interface, where we can proxy calls to the Umbraco logger to use an underlying Serilog ILogger. With this then done to get Umbraco to use this we simply need to update the Global.asax file on disk to inherit from our new class that is overriding the UmbracoApplication GetLogger method.

Some prerequisites

So for the code example below to work you will need the following Nuget packages installed and a copy of Seq installed, which has a FREE single-user license to run Seq locally

Get to the code

using System;
using Serilog;
using Serilog.Core;
using Umbraco.Web;
using ILogger = Umbraco.Core.Logging.ILogger;

namespace MyProject
{
    public class SwapLogging : UmbracoApplication
    {
        protected override ILogger GetLogger()
        {
            var customLogger = new SeriLogger();
            return customLogger;
        }
    }

    /// <summary>
    /// Not the nicest but we need to implement Umbraco's own ILogger
    /// To call/wrap the underlying Serilog calls
    /// </summary>
    public class SeriLogger : ILogger
    {
        private Logger _seriLogger;

        public SeriLogger()
        {
            var basedir = AppDomain.CurrentDomain.BaseDirectory;
            var appDomainId = AppDomain.CurrentDomain.Id;

            //Configure &amp; setup SeriLogger with Sinks &amp; Enrichers
            //Sinks are where we want to push log data to
            //Enrichers add extra properties/information to enhance the log item
            //TODO: Move to a config file - https://github.com/serilog/serilog/wiki/AppSettings
            _seriLogger = new LoggerConfiguration()
                .MinimumLevel.Verbose()
                .Enrich.WithProcessId()
                .Enrich.WithProcessName()
                .Enrich.WithThreadId()
                .Enrich.WithProperty("DomainId", appDomainId) //We can add our own properties to logs
                .Enrich.WithProperty("BaseDirectory", basedir)
                .WriteTo.RollingFile(basedir + "\\logs\\New-UmbracoLogFile-{Date}.txt",
                    outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [P{ProcessId}/D{DomainId}/T{ThreadId}] {Level:u} {SourceContext} - {Message}{NewLine}{Exception}") //We can define what format we want the text logfile to be output as
                .WriteTo.Seq("http://localhost:5341")
                .CreateLogger();
        }

        public void Error(Type reporting, string message, Exception exception = null)
        {
            _seriLogger
                .ForContext(reporting)
                .Error(exception, message);
        }

        public void Warn(Type reporting, string message)
        {
            _seriLogger
                .ForContext(reporting)
                .Warning(message);
        }

        public void Warn(Type reporting, Func messageBuilder)
        {
            _seriLogger
                .ForContext(reporting)
                .Warning(messageBuilder());
        }

        public void Warn(Type reporting, Exception exception, string message)
        {
            _seriLogger
                .ForContext(reporting)
                .Warning(exception, message);
        }

        public void Warn(Type reporting, Exception exception, Func messageBuilder)
        {
            _seriLogger
                .ForContext(reporting)
                .Warning(exception, messageBuilder());
        }

        public void Info(Type reporting, string message)
        {
            _seriLogger
                .ForContext(reporting)
                .Information(message);
        }

        public void Info(Type reporting, Func messageBuilder)
        {
            _seriLogger
                .ForContext(reporting)
                .Information(messageBuilder());
        }

        public void Debug(Type reporting, string message)
        {
            _seriLogger
                .ForContext(reporting)
                .Debug(message);
        }

        public void Debug(Type reporting, Func messageBuilder)
        {
            _seriLogger
                .ForContext(reporting)
                .Debug(messageBuilder());
        }
    }
}

I’m not convinced, show me it works!

With all magic tricks there is some skepticism, so to be fully transparent and to ensure you its working here is a view of logs coming from Umbraco V8 in my local copy of Seq.

A quick screenshot of my local copy of Seq with Umbraco V8 logs and additional properties pushed in

Tada!

OK so now you know how the magic is done, I would like to hear back via twitter or comments on this post, if this is something useful to have learnt or was this is just a pointless experiment, either way I would love to hear back from you.

Thanks,
Warren 🙂