Skip to content

Commit

Permalink
feat: Provide better usability in terms of startup and configuration …
Browse files Browse the repository at this point in the history
…insights (#1474)

* List all validation steps as table

Signed-off-by: Tom Kerkhove <kerkhove.tom@gmail.com>

* Provide better usability in terms of startup and configuration insights

Signed-off-by: Tom Kerkhove <kerkhove.tom@gmail.com>

* Thank you!

Signed-off-by: Tom Kerkhove <kerkhove.tom@gmail.com>

* List discovery groups

Signed-off-by: Tom Kerkhove <kerkhove.tom@gmail.com>
  • Loading branch information
tomkerkhove authored Feb 3, 2021
1 parent 5b55cbd commit ca19d06
Show file tree
Hide file tree
Showing 18 changed files with 317 additions and 35 deletions.
2 changes: 2 additions & 0 deletions config/promitor/scraper/metrics.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ metrics:
- name: promitor_demo_appplan_percentage_cpu
description: "Average percentage of memory usage on an Azure App Plan"
resourceType: AppPlan
labels:
app: promitor
azureMetricConfiguration:
metricName: MemoryPercentage
aggregation:
Expand Down
4 changes: 2 additions & 2 deletions config/promitor/scraper/runtime.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ telemetry:
verbosity: warning
containerLogs:
isEnabled: true
verbosity: trace
defaultVerbosity: trace
verbosity: information
defaultVerbosity: information
azureMonitor:
logging:
informationLevel: Headers
Expand Down
4 changes: 4 additions & 0 deletions docs/thank-you.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ Here is an overview of the NuGet packages that we rely on:
- Swagger tools for documenting API's built on ASP.NET Core
- [Prometheus.Client](https://github.com/PrometheusClientNet/Prometheus.Client)
- .NET client for prometheus.io
- [spectre.console](https://github.com/spectresystems/spectre.console) - A library that makes it easier to create
beautiful console applications.
- [Humanizer](https://github.com/Humanizr/Humanizer) - Humanizer meets all your .NET needs for manipulating and
displaying strings, enums, dates, times, timespans, numbers and quantities
- [YamlDotNet](https://github.com/aaubry/YamlDotNet) - .NET library for YAML
- [Guard.NET](https://github.com/george-pancescu/Guard) - Library that facilitates
runtime checks of code and allows to define preconditions and invariants within
Expand Down
3 changes: 3 additions & 0 deletions src/Promitor.Agents.Core/Promitor.Agents.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@
<PackageReference Include="NetEscapades.Configuration.Yaml" Version="2.1.0" />
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
<PackageReference Include="Spectre.Console" Version="0.37.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="5.6.3" />
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="6.0.1" />
<PackageReference Include="Humanizer" Version="2.8.26" />
<PackageReference Include="Spectre.Console" Version="0.37.0" />
</ItemGroup>

<ItemGroup>
Expand Down
22 changes: 22 additions & 0 deletions src/Promitor.Agents.Core/Usability/AsciiTableGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Spectre.Console;

namespace Promitor.Agents.Core.Usability
{
public class AsciiTableGenerator
{
protected Table CreateAsciiTable(string caption = null)
{
var asciiTable = new Table
{
Border = TableBorder.Rounded
};

if(string.IsNullOrWhiteSpace(caption) == false)
{
asciiTable.Caption(caption);
}

return asciiTable;
}
}
}
30 changes: 25 additions & 5 deletions src/Promitor.Agents.Core/Validation/RuntimeValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Linq;
using Microsoft.Extensions.Logging;
using Promitor.Agents.Core.Validation.Interfaces;
using Spectre.Console;

#pragma warning disable 618
namespace Promitor.Agents.Core.Validation
Expand Down Expand Up @@ -43,29 +44,48 @@ private List<ValidationResult> RunValidationSteps()

var totalValidationSteps = _validationSteps.Count;
var validationResults = new List<ValidationResult>();

// Create a table
var asciiTable = CreateAsciiTable();

for (var currentValidationStep = 1; currentValidationStep <= totalValidationSteps; currentValidationStep++)
{
var validationStep = _validationSteps[currentValidationStep - 1];
var validationResult = RunValidationStep(validationStep, currentValidationStep, totalValidationSteps);
var validationResult = RunValidationStep(validationStep, asciiTable);
validationResults.Add(validationResult);
}

AnsiConsole.Render(asciiTable);

return validationResults;
}

private ValidationResult RunValidationStep(IValidationStep validationStep, int currentStep, int totalSteps)
private static Table CreateAsciiTable()
{
_validationLogger.LogInformation("Start Validation step {currentStep}/{totalSteps}: {validationStepName}", currentStep, totalSteps, validationStep.ComponentName);
var asciiTable = new Table
{
Border = TableBorder.HeavyEdge
};

// Add some columns
asciiTable.AddColumn("Name");
asciiTable.AddColumn("Outcome");
asciiTable.AddColumn("Details");
asciiTable.Caption("Validation");

return asciiTable;
}

private ValidationResult RunValidationStep(IValidationStep validationStep, Table asciiTable)
{
var validationResult = validationStep.Run();
if (validationResult.IsSuccessful)
{
_validationLogger.LogInformation("Validation step {currentStep}/{totalSteps} succeeded", currentStep, totalSteps);
asciiTable.AddRow(validationStep.ComponentName, "Success", "Everything is well-configured.");
}
else
{
_validationLogger.LogWarning("Validation step {currentStep}/{totalSteps} failed. Error(s): {validationMessage}", currentStep, totalSteps, validationResult.Message);
asciiTable.AddRow(validationStep.ComponentName, "Failed", $"Validation failed:\r\n{validationResult.Message}");
}

return validationResult;
Expand Down
10 changes: 10 additions & 0 deletions src/Promitor.Agents.ResourceDiscovery/Docs/Open-Api.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Promitor.Agents.ResourceDiscovery.Graph.Interfaces;
using Promitor.Agents.ResourceDiscovery.Repositories;
using Promitor.Agents.ResourceDiscovery.Repositories.Interfaces;
using Promitor.Agents.ResourceDiscovery.Usability;
using Promitor.Agents.ResourceDiscovery.Validation.Steps;

namespace Promitor.Agents.ResourceDiscovery.Extensions
Expand Down Expand Up @@ -71,5 +72,15 @@ public static IServiceCollection AddValidationRules(this IServiceCollection serv

return services;
}

/// <summary>
/// Add usability
/// </summary>
public static IServiceCollection AddUsability(this IServiceCollection services)
{
services.AddTransient<DiscoveryGroupTableGenerator>();

return services;
}
}
}
9 changes: 9 additions & 0 deletions src/Promitor.Agents.ResourceDiscovery/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Promitor.Agents.Core.Configuration.Server;
using Promitor.Agents.Core.Extensions;
using Promitor.Agents.Core.Validation;
using Promitor.Agents.ResourceDiscovery.Usability;
using Promitor.Core;
using Serilog;

Expand Down Expand Up @@ -43,6 +44,7 @@ public static int Main(string[] args)
}

Log.Logger.Information("Promitor configuration is valid, we are good to go.");
PlotConfiguredDiscoveryGroups(scope);
}

host.Run();
Expand Down Expand Up @@ -93,5 +95,12 @@ private static IConfiguration BuildConfiguration(string[] args, string configura

return configuration;
}

private static void PlotConfiguredDiscoveryGroups(IServiceScope scope)
{
var metricsTableGenerator = scope.ServiceProvider.GetRequiredService<DiscoveryGroupTableGenerator>();
Log.Logger.Information("Here's an overview of what was configured:");
metricsTableGenerator.PlotOverviewInAsciiTable();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
<ItemGroup>
<ProjectReference Include="..\Promitor.Agents.Core\Promitor.Agents.Core.csproj" />
<ProjectReference Include="..\Promitor.Core.Contracts\Promitor.Core.Contracts.csproj" />
<ProjectReference Include="..\Promitor.Core.Scraping\Promitor.Core.Scraping.csproj" />
</ItemGroup>

</Project>
1 change: 1 addition & 0 deletions src/Promitor.Agents.ResourceDiscovery/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public void ConfigureServices(IServiceCollection services)
.AddMemoryCache()
.AddRuntimeConfiguration(Configuration)
.AddAzureResourceGraph(Configuration)
.AddUsability()
.UseOpenApiSpecifications($"{ApiName} v1", ApiDescription, 1)
.AddValidationRules()
.AddHttpCorrelation()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using GuardNet;
using Humanizer;
using Microsoft.Extensions.Options;
using Promitor.Agents.Core.Usability;
using Promitor.Agents.ResourceDiscovery.Configuration;
using Spectre.Console;

namespace Promitor.Agents.ResourceDiscovery.Usability
{
public class DiscoveryGroupTableGenerator : AsciiTableGenerator
{
private readonly IOptionsMonitor<ResourceDeclaration> _resourceDeclarationMonitor;

public DiscoveryGroupTableGenerator(IOptionsMonitor<ResourceDeclaration> resourceDeclarationMonitor)
{
Guard.NotNull(resourceDeclarationMonitor, nameof(resourceDeclarationMonitor));

_resourceDeclarationMonitor = resourceDeclarationMonitor;
}

/// <summary>
/// Plots all configured information into an ASCII table
/// </summary>
public void PlotOverviewInAsciiTable()
{
var resourceDeclaration = _resourceDeclarationMonitor.CurrentValue;
PlotAzureMetadataInAsciiTable(resourceDeclaration.AzureLandscape);
PlotResourceDiscoveryGroupsInAsciiTable(resourceDeclaration.ResourceDiscoveryGroups);
}

private void PlotResourceDiscoveryGroupsInAsciiTable(List<ResourceDiscoveryGroup> resourceDiscoveryGroups)
{
var asciiTable = CreateResourceDiscoveryGroupsAsciiTable();

foreach (var resourceDiscoveryGroup in resourceDiscoveryGroups)
{
var isInclusionCriteriaConfigured = resourceDiscoveryGroup.Criteria.Include != null ? "Yes" : "No";
asciiTable.AddRow(resourceDiscoveryGroup.Name, resourceDiscoveryGroup.Type.Humanize(LetterCasing.Title), isInclusionCriteriaConfigured);
}

AnsiConsole.Render(asciiTable);
}

private void PlotAzureMetadataInAsciiTable(AzureLandscape azureLandscape)
{
var asciiTable = CreateAzureMetadataAsciiTable();

var rawSubscriptions = "- " + string.Join($"{Environment.NewLine} - ", azureLandscape.Subscriptions);

asciiTable.AddRow(azureLandscape.TenantId, azureLandscape.Cloud.Humanize(LetterCasing.Title), rawSubscriptions);

AnsiConsole.Render(asciiTable);
}

private Table CreateResourceDiscoveryGroupsAsciiTable()
{
var asciiTable = CreateAsciiTable("Resource Discovery Groups");

// Add some columns
asciiTable.AddColumn("Name");
asciiTable.AddColumn("Resource Type");
asciiTable.AddColumn("Is Include Criteria Configured?");

return asciiTable;
}

private Table CreateAzureMetadataAsciiTable()
{
var asciiTable = CreateAsciiTable("Azure Landscape");

// Add some columns
asciiTable.AddColumn("Tenant Id");
asciiTable.AddColumn("Azure Cloud");
asciiTable.AddColumn("Subscriptions");

return asciiTable;
}
}
}
11 changes: 11 additions & 0 deletions src/Promitor.Agents.Scraper/Docs/Open-Api.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using Promitor.Agents.Scraper.Configuration;
using Promitor.Agents.Scraper.Configuration.Sinks;
using Promitor.Agents.Scraper.Discovery;
using Promitor.Agents.Scraper.Usability;
using Promitor.Agents.Scraper.Validation.Steps;
using Promitor.Agents.Scraper.Validation.Steps.Sinks;
using Promitor.Core;
Expand Down Expand Up @@ -113,6 +114,17 @@ public static IServiceCollection DefineDependencies(this IServiceCollection serv
return services;
}

/// <summary>
/// Adds usability
/// </summary>
/// <param name="services">Collections of services in application</param>
public static IServiceCollection AddUsability(this IServiceCollection services)
{
services.AddTransient<MetricsTableGenerator>();

return services;
}

/// <summary>
/// Defines the validation for when Promitor starts up
/// </summary>
Expand Down
12 changes: 11 additions & 1 deletion src/Promitor.Agents.Scraper/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Promitor.Agents.Core.Configuration.Server;
using Promitor.Agents.Core.Extensions;
using Promitor.Agents.Core.Validation;
using Promitor.Agents.Scraper.Usability;
using Promitor.Core;
using Serilog;

Expand Down Expand Up @@ -43,7 +44,9 @@ public static int Main(string[] args)
return (int)ExitStatus.ValidationFailed;
}

Log.Logger.Information("Promitor configuration is valid, we are good to go.");
Log.Logger.Information("Promitor configuration is valid, we are good to go.");

PlotConfiguredMetrics(scope);
}

host.Run();
Expand Down Expand Up @@ -93,5 +96,12 @@ private static IConfigurationRoot BuildConfiguration(string configurationFolder)

return configuration;
}

private static void PlotConfiguredMetrics(IServiceScope scope)
{
var metricsTableGenerator = scope.ServiceProvider.GetRequiredService<MetricsTableGenerator>();
Log.Logger.Information("Here's an overview of what was configured:");
metricsTableGenerator.PlotOverviewInAsciiTable();
}
}
}
1 change: 1 addition & 0 deletions src/Promitor.Agents.Scraper/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public void ConfigureServices(IServiceCollection services)
services.UseWebApi()
.AddResourceDiscoveryClient(promitorUserAgent)
.AddAtlassianStatuspageClient(promitorUserAgent, Configuration)
.AddUsability()
.AddHttpCorrelation()
.AddAutoMapper(typeof(V1MappingProfile).Assembly)
.DefineDependencies()
Expand Down
Loading

0 comments on commit ca19d06

Please sign in to comment.