From 357137d1800d6fd38c1fcb33fb4a9f902247d1fa Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 22 Mar 2022 17:04:51 +0100 Subject: [PATCH] Better CLI logging. --- .../Apps/Templates/CLILogger.cs | 59 ---------- .../Apps/Templates/StringLogger.cs | 110 ++++++++++++++++++ .../Templates/TemplateCommandMiddleware.cs | 43 ++++--- 3 files changed, 136 insertions(+), 76 deletions(-) delete mode 100644 backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CLILogger.cs create mode 100644 backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/StringLogger.cs diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CLILogger.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CLILogger.cs deleted file mode 100644 index dcf60fc0b..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CLILogger.cs +++ /dev/null @@ -1,59 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Squidex.CLI.Commands.Implementation; -using Squidex.Infrastructure; - -namespace Squidex.Domain.Apps.Entities.Apps.Templates -{ - internal sealed class CLILogger : ILogger, ILogLine - { - public static readonly CLILogger Instance = new CLILogger(); - - private CLILogger() - { - } - - public void StepFailed(string reason) - { - throw new DomainException($"Template failed with {reason}"); - } - - public void StepSkipped(string reason) - { - } - - public void StepStart(string process) - { - } - - public void StepSuccess(string? details = null) - { - } - - public void WriteLine() - { - } - - public void WriteLine(string message) - { - } - - public void WriteLine(string message, params object?[] args) - { - } - - public void Dispose() - { - } - - public ILogLine WriteSameLine() - { - return this; - } - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/StringLogger.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/StringLogger.cs new file mode 100644 index 000000000..1d0ae5e14 --- /dev/null +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/StringLogger.cs @@ -0,0 +1,110 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Globalization; +using Microsoft.Extensions.Logging; +using Squidex.CLI.Commands.Implementation; +using Squidex.Infrastructure; +using ILog = Microsoft.Extensions.Logging.ILogger; + +namespace Squidex.Domain.Apps.Entities.Apps.Templates +{ + public sealed class StringLogger : CLI.Commands.Implementation.ILogger, ILogLine + { + private const int MaxActionLength = 40; + private readonly ILog log; + private readonly List lines = new List(); + private readonly List errors = new List(); + private string startedLine = string.Empty; + + public StringLogger(ILog log) + { + this.log = log; + } + + public void Dispose() + { + var mesage = string.Join('\n', lines); + + log.LogInformation("CLI executed with full logs {steps}.", mesage); + + if (errors.Count > 0) + { + throw new DomainException($"Template failed with {errors[0]}"); + } + } + + public void StepStart(string message) + { + if (message.Length > MaxActionLength - 3) + { + var length = MaxActionLength - 3; + + message = message[..length]; + } + + startedLine = $"{message.PadRight(MaxActionLength, '.')}..."; + } + + public void StepSuccess(string? details = null) + { + if (!string.IsNullOrWhiteSpace(details)) + { + AddToLine($"succeeded ({details})."); + } + else + { + AddToLine("succeeded"); + } + } + + public void StepFailed(string reason) + { + AddToErrors(reason); + AddToLine($"failed: {reason.TrimEnd('.')}."); + } + + public void StepSkipped(string reason) + { + AddToLine($"skipped: {reason.TrimEnd('.')}."); + } + + public void WriteLine() + { + lines.Add(string.Empty); + } + + public void WriteLine(string message) + { + lines.Add(message); + } + + public void WriteLine(string message, params object?[] args) + { + lines.Add(string.Format(CultureInfo.InvariantCulture, message, args)); + } + + private void AddToErrors(string reason) + { + errors.Add(reason); + } + + private void AddToLine(string message) + { + startedLine += message; + + lines.Add(startedLine); + + startedLine = string.Empty; + } + + public ILogLine WriteSameLine() + { + return this; + } + } +} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/TemplateCommandMiddleware.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/TemplateCommandMiddleware.cs index 6c24693f3..efd00b199 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/TemplateCommandMiddleware.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/TemplateCommandMiddleware.cs @@ -5,6 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using Microsoft.Extensions.Logging; using Squidex.CLI.Commands.Implementation; using Squidex.CLI.Commands.Implementation.FileSystem; using Squidex.CLI.Commands.Implementation.Sync; @@ -27,20 +28,14 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates { private readonly TemplatesClient templatesClient; private readonly IUrlGenerator urlGenerator; - private readonly ISynchronizer[] targets = - { - new AppSynchronizer(CLILogger.Instance), - new AssetFoldersSynchronizer(CLILogger.Instance), - new AssetsSynchronizer(CLILogger.Instance), - new RulesSynchronizer(CLILogger.Instance), - new SchemasSynchronizer(CLILogger.Instance), - new WorkflowsSynchronizer(CLILogger.Instance), - }; - - public TemplateCommandMiddleware(TemplatesClient templatesClient, IUrlGenerator urlGenerator) + private readonly ILogger log; + + public TemplateCommandMiddleware(TemplatesClient templatesClient, IUrlGenerator urlGenerator, + ILogger log) { this.templatesClient = templatesClient; this.urlGenerator = urlGenerator; + this.log = log; } public async Task HandleAsync(CommandContext context, NextDelegate next) @@ -64,17 +59,31 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates if (string.IsNullOrEmpty(repository)) { + log.LogWarning("Cannot find template {template}.", template); return; } - var session = CreateSession(app); + using (var cliLog = new StringLogger(log)) + { + var session = CreateSession(app); - var syncService = await CreateSyncServiceAsync(repository, session); - var syncOptions = new SyncOptions(); + var syncService = await CreateSyncServiceAsync(repository, session); + var syncOptions = new SyncOptions(); - foreach (var target in targets.OrderBy(x => x.Name)) - { - await target.ImportAsync(syncService, syncOptions, session); + var targets = new ISynchronizer[] + { + new AppSynchronizer(cliLog), + new AssetFoldersSynchronizer(cliLog), + new AssetsSynchronizer(cliLog), + new RulesSynchronizer(cliLog), + new SchemasSynchronizer(cliLog), + new WorkflowsSynchronizer(cliLog), + }; + + foreach (var target in targets.OrderBy(x => x.Name)) + { + await target.ImportAsync(syncService, syncOptions, session); + } } }