Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V8 LogViewer #2926

Merged
merged 139 commits into from
Jan 22, 2019
Merged

V8 LogViewer #2926

merged 139 commits into from
Jan 22, 2019

Conversation

warrenbuckley
Copy link
Contributor

@warrenbuckley warrenbuckley commented Sep 6, 2018

This is a work in progress to consider adding in a built in LogViewer to Umbraco V8 Core

Why do this?

Currently, for all Cloud sites, we use a community package called Trace Log Viewer which is a popular community package.

It makes sense to have this part of the core Umbraco product to have a way to view, filter and query the logs that we are reporting from Umbraco, as opposed to a community package. This way everyone benefits from it, not just sites running on Umbraco Cloud.

With the upcoming Umbraco Headless project, there is no direct file access and this will be the only way for customers to see & view the logs that the Umbraco headless project is reporting.

What does it do?

This PR adds in a new tree to the Developer section called Logs that allows users to:

  • View logs directly in the backoffice
  • Filter/toggle logs by log level
  • Quick glance of number of errors
  • Chart displaying the distribution of log level types
  • List of most common log message templates, to determine common log patterns or errors
  • Perform advanced expression/searches to find logs

Extending/swapping out the LogViewer datasource

It is possible to swap out the default LogViewer datasource from reading the JSON files off disk, by disabling the Umbraco core component and registering our own component to put into the DI container.

The example below reads JSON logs stored in Azure Table Storage, that a user may configure V8 to store logs with Serilog to be logged into Azure Table storage with the off shelf Serilog sink.

Setup

  • Install Serilog.Sinks.AzureTableStorage from Nuget (Latest pre-release)
  • Update `config/serilog.user.config with credentials (so logs persist to Azure)
<add key="serilog:using:AzureTableStorage" value="Serilog.Sinks.AzureTableStorage" />
<add key="serilog:write-to:AzureTableStorage.connectionString" value="DefaultEndpointsProtocol=https;AccountName=ACCOUNT_NAME;AccountKey=KEY;EndpointSuffix=core.windows.net" />
<add key="serilog:write-to:AzureTableStorage.formatter" value="Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact" />

Register component (that disables the core one)

using Umbraco.Core.Components;
using Umbraco.Core.Composing;
using Umbraco.Core.Logging.Viewer;

namespace Umbraco.Web.UI
{
    [DisableComponent(typeof(LogViewerComponent))]
    public class AzureTableLogComponent : UmbracoComponentBase, IUmbracoUserComponent
    {
        public override void Compose(Composition composition)
        {
            composition.Container.RegisterSingleton<ILogViewer, AzureTableLogViewer>();
        }
    }
}

Implement ILogViewer

using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
using Serilog.Events;
using Serilog.Formatting.Compact.Reader;
using Serilog.Sinks.AzureTableStorage;
using System;
using System.Collections.Generic;
using Umbraco.Core.Logging.Viewer;

namespace Umbraco.Web.UI
{
    public class AzureTableLogViewer : LogViewerSourceBase
    {
        
        public override bool CanHandleLargeLogs => true;

        public override bool CheckCanOpenLogs(DateTimeOffset startDate, DateTimeOffset endDate)
        {
            //This method will not be called - as we have indicated that this 'CanHandleLargeLogs'
            throw new NotImplementedException();
        }

        public override IEnumerable<LogEvent> GetLogs(DateTimeOffset startDate, DateTimeOffset endDate, ILogFilter filter, int skip, int take)
        {
            var cloudStorage = CloudStorageAccount.Parse("DefaultEndpointsProtocol=https;AccountName=warrenlogstorage;AccountKey=/NuiVmUiRkPmkg+zY/Gnz5/Lw1ErxZm8cW2XwR4DwhoMvJ0TSo987nSW7lDJHrciW2EyaZv948DLz+GJujqjnA==;EndpointSuffix=core.windows.net");
            var tableClient = cloudStorage.CreateCloudTableClient();
            var table = tableClient.GetTableReference("LogEventEntity");

            var logs = new List<LogEvent>();
            var count = 0;
            
            // Create the table query
            // TODO: Use a range query to filter by start & end date on the Timestamp
            var query = new TableQuery<LogEventEntity>();
            var results = table.ExecuteQuery(query);

            // Loop through the results, displaying information about the entity.
            foreach (var entity in results)
            {
                //Reads the compact JSON format stored in the 'Data' column back to a LogEvent
                //Same as the JSON txt files does
                var logItem = LogEventReader.ReadFromString(entity.Data);
                
                if (count > skip + take)
                {
                    break;
                }

                if (count < skip)
                {
                    count++;
                    continue;
                }

                if (filter.TakeLogEvent(logItem))
                {
                    logs.Add(logItem);
                }

                count++;
            }

            return logs;
        }
    }
}

TODO:

  • Date picker range & filtering for logs Removed for first iteration
  • Total count for distinct message templates
  • Search/Filter dropdown for common searches (Base it on Content Node Name Variants)
  • Fix Error exception message styling - rather than big ugly red background
  • Click a common logtemplate - performs the search/expression for that messagetemplate

Warren added 25 commits August 24, 2018 10:53
…ill have to disable this component & register their own implementation)

Get some more of the basic WebAPI stubs fleshed out to get some data to start using in the UI layer
…gviewer

# Conflicts:
#	src/Umbraco.Web.UI.Client/bower.json
…y as we have a LogController already for audit logs
…ing up loggers to query the same LogEvents loaded into memory

* StartsWith(SourceContext, 'Umbraco.Core')
* StartsWith(SourceContext, 'Umbraco.Core') and @MessageTemplate='[Timing {TimingId}] {EndMessage} ({TimingDuration}ms)'
* @MessageTemplate='[Timing {TimingId}] {EndMessage} ({TimingDuration}ms)' and TimingDuration > 1000
* List number of total errors
* Pie Chart of log level counts
* Message counts
* Log items with paging & searching
* Toggle timestamp order by ascending or descending
…rialised EX back to proper exceptions so we call ToString on it instead
* Output ex nicer
* Add log level colours to badges
* Output date in friendlier format
…arty devs. Say from Azure Table Storage for example
@ghost ghost assigned warrenbuckley Sep 6, 2018
@warrenbuckley
Copy link
Contributor Author

warrenbuckley commented Sep 6, 2018

@Shazwazza & @zpqrtbnk I would love some early tech/code review on this please before I code myself into a corner & to ensure it is performant as it can be, Thx 😄

Warren Buckley added 3 commits September 7, 2018 21:43
…plates and their counts

In the UI we display the total count of unique but use LimitTo AngularJS filter to continue to display 10 items
Returning all items so that we have a way to show the next 10 items or similar
…an a massive RED background

Starts work on getting the dropdown for some example queries setup
Warren Buckley added 14 commits January 1, 2019 19:08
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js
# Conflicts:
#	src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs
# Conflicts:
#	src/Umbraco.Web.UI.Client/package-lock.json
# Conflicts:
#	src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs
#	src/Umbraco.Web.UI.Client/gulpfile.js
#	src/Umbraco.Web.UI/config/trees.Release.config
#	src/Umbraco.Web.UI/config/trees.config
…t parameters with DI hence needed to use factory & new up an instance
@bergmania bergmania self-assigned this Jan 22, 2019
@bergmania bergmania merged commit 4981f0e into temp8 Jan 22, 2019
@ghost ghost removed the state/review label Jan 22, 2019
@bergmania bergmania deleted the temp8-logviewer branch January 22, 2019 11:04
@clausjensen clausjensen added this to the sprint103 milestone Jan 24, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants