Skip to content

Commit

Permalink
Metric deserialization refactor (#439)
Browse files Browse the repository at this point in the history
Fixes #416 

## Proposed Changes
The approach here is to move the deserializing of metric configuration from the Promitor YAML file in to a more decomposed approach. This allows for new metrics & scrapers to be added without risking merge conflicts as changes are isolated to specific files only pertaining to the metrics and deserialization thereof; not within a host of methods inside one specific file.

Documentation for 'adding a scraper' has also been updated to be more descriptive & prescriptive on the metric deserialization procedure when new metrics are added.
  • Loading branch information
brandonh-msft authored and tomkerkhove committed Mar 26, 2019
1 parent 7a2ac8f commit 2c72d10
Show file tree
Hide file tree
Showing 26 changed files with 208 additions and 137 deletions.
9 changes: 5 additions & 4 deletions adding-a-new-scraper.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ This guide walks you through the process of adding a new scraper type.
-------------------------

## Configuration
1. Add your new scraping type to `ResourceType`
2. Describe what your configuration by creating `<New-Type>MetricDefinition`and inherit from `MetricDefinition`
3. Update the deserialization to support your new type in `MetricsDeserializer`
4. Provide a unit test that tests the deserialization based on our sample
1. Add your new scraping type to the `Promitor.Core.Scraping.Configuration.Model.ResourceType`
2. Describe the resource for which you're creating scraping metrics by creating `<New-Type>MetricDefinition`and inherit from `Promitor.Core.Scraping.Configuration.Model.Metrics.MetricDefinition` - this class should go in `.\src\Promitor.Core.Scraping\Configuration\Model\Metrics\ResourceTypes`
3. Create a new Deserializer in `.\src\Promitor.Core.Scraping\Configuration\Serialization\Deserializers`. This must inherit from `AzureMetricDeserializer`.
3. Update `Promitor.Core.Scraping.Factories.MetricDeserializerFactory` to handle your new resource type by returning a new instance of the Deserializer you created in the previous step.
4. Provide a unit test in `.\src\Promitor.Scraper.Tests.Unit\Serialization\MetricsDeclaration\` that tests the deserialization based on our sample

Going forward in this guide, `TMetricDefinition` will refer to your newly created configuration type.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace Promitor.Core.Scraping.Configuration.Model.Metrics
{
public class MetricDefinition
public abstract class MetricDefinition
{
/// <summary>
/// Configuration about the Azure Monitor metric to scrape
Expand All @@ -20,6 +20,6 @@ public class MetricDefinition
/// <summary>
/// Type of resource that is configured
/// </summary>
public virtual ResourceType ResourceType { get; set; }
public abstract ResourceType ResourceType { get; }
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
namespace Promitor.Core.Scraping.Configuration.Model.Metrics.ResourceTypes
{
public class GenericMetricDefinition : MetricDefinition
public class GenericAzureMetricDefinition : MetricDefinition
{
public string Filter { get; set; }
public override ResourceType ResourceType { get; set; } = ResourceType.Generic;
public override ResourceType ResourceType { get; } = ResourceType.Generic;
public string ResourceUri { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ public class ServiceBusQueueMetricDefinition : MetricDefinition
{
public string Namespace { get; set; }
public string QueueName { get; set; }
public override ResourceType ResourceType { get; set; } = ResourceType.ServiceBusQueue;
public override ResourceType ResourceType { get; } = ResourceType.ServiceBusQueue;
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
namespace Promitor.Core.Scraping.Configuration.Model.Metrics.ResourceTypes
{
public class StorageQueueMetricDefinition: MetricDefinition
public class StorageQueueMetricDefinition : MetricDefinition
{
public string AccountName { get; set; }
public string QueueName { get; set; }
public string SasToken { get; set; }
public override ResourceType ResourceType { get; set; } = ResourceType.StorageQueue;
public override ResourceType ResourceType { get; } = ResourceType.StorageQueue;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using Microsoft.Extensions.Logging;
using Promitor.Core.Scraping.Configuration.Model;
using Promitor.Core.Scraping.Configuration.Providers.Interfaces;
using Promitor.Core.Scraping.Configuration.Serialization;
using Promitor.Core.Scraping.Configuration.Serialization.Core;

namespace Promitor.Core.Scraping.Configuration.Providers
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using Promitor.Core.Scraping.Configuration.Model;
using YamlDotNet.RepresentationModel;

namespace Promitor.Core.Scraping.Configuration.Serialization
namespace Promitor.Core.Scraping.Configuration.Serialization.Core
{
internal class AggregationDeserializer : Deserializer<Aggregation>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using Promitor.Core.Scraping.Configuration.Model;
using YamlDotNet.RepresentationModel;

namespace Promitor.Core.Scraping.Configuration.Serialization
namespace Promitor.Core.Scraping.Configuration.Serialization.Core
{
internal class AzureMetadataDeserializer : Deserializer<AzureMetadata>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using Promitor.Core.Scraping.Configuration.Model;
using YamlDotNet.RepresentationModel;

namespace Promitor.Core.Scraping.Configuration.Serialization
namespace Promitor.Core.Scraping.Configuration.Serialization.Core
{
internal class AzureMetricConfigurationDeserializer : Deserializer<AzureMetricConfiguration>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
using Promitor.Core.Serialization.Yaml;
using YamlDotNet.RepresentationModel;

namespace Promitor.Core.Scraping.Configuration.Serialization
namespace Promitor.Core.Scraping.Configuration.Serialization.Core
{
public class ConfigurationSerializer
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using Microsoft.Extensions.Logging;
using YamlDotNet.RepresentationModel;

namespace Promitor.Core.Scraping.Configuration.Serialization
namespace Promitor.Core.Scraping.Configuration.Serialization.Core
{
internal abstract class Deserializer<TObject>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using Promitor.Core.Scraping.Configuration.Model;
using YamlDotNet.RepresentationModel;

namespace Promitor.Core.Scraping.Configuration.Serialization
namespace Promitor.Core.Scraping.Configuration.Serialization.Core
{
internal class MetricAggregationDeserializer : Deserializer<MetricAggregation>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using Promitor.Core.Scraping.Configuration.Model;
using YamlDotNet.RepresentationModel;

namespace Promitor.Core.Scraping.Configuration.Serialization
namespace Promitor.Core.Scraping.Configuration.Serialization.Core
{
internal class MetricDefaultsDeserializer : Deserializer<MetricDefaults>
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using GuardNet;
using Microsoft.Extensions.Logging;
using Promitor.Core.Scraping.Configuration.Model.Metrics;
using YamlDotNet.RepresentationModel;

namespace Promitor.Core.Scraping.Configuration.Serialization.Core
{
internal abstract class MetricDeserializer
{
protected ILogger Logger { get; private set; }

internal MetricDeserializer WithLogger(ILogger logger)
{
Guard.NotNull(logger, nameof(logger));

Logger = logger;
return this;
}

internal abstract MetricDefinition Deserialize(YamlMappingNode metricNode);

protected virtual TMetricDefinition DeserializeMetricDefinition<TMetricDefinition>(YamlMappingNode metricNode)
where TMetricDefinition : MetricDefinition, new()
{
Guard.NotNull(metricNode, nameof(metricNode));

var name = metricNode.Children[new YamlScalarNode("name")];
var description = metricNode.Children[new YamlScalarNode("description")];
var azureMetricConfigurationNode = (YamlMappingNode)metricNode.Children[new YamlScalarNode("azureMetricConfiguration")];

var azureMetricConfigurationDeserializer = new AzureMetricConfigurationDeserializer(Logger);
var azureMetricConfiguration = azureMetricConfigurationDeserializer.Deserialize(azureMetricConfigurationNode);

var metricDefinition = new TMetricDefinition
{
Name = name?.ToString(),
Description = description?.ToString(),
AzureMetricConfiguration = azureMetricConfiguration
};

return metricDefinition;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using Microsoft.Extensions.Logging;
using Promitor.Core.Scraping.Configuration.Model;
using Promitor.Core.Scraping.Configuration.Model.Metrics;
using Promitor.Core.Scraping.Factories;
using YamlDotNet.RepresentationModel;

namespace Promitor.Core.Scraping.Configuration.Serialization.Core
{
internal class MetricsDeserializer : Deserializer<MetricDefinition>
{
internal MetricsDeserializer(ILogger logger) : base(logger)
{
}

internal override MetricDefinition Deserialize(YamlMappingNode node)
{
var rawResourceType = node.Children[new YamlScalarNode("resourceType")];

if (!Enum.TryParse<ResourceType>(rawResourceType.ToString(), out var resourceType))
{
throw new ArgumentException($@"Unknown 'resourceType' value in metric configuration: {rawResourceType}");
}

return MetricDeserializerFactory
.GetDeserializerFor(resourceType)
.WithLogger(Logger)
.Deserialize(node);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Promitor.Core.Scraping.Configuration.Model.Metrics;
using Promitor.Core.Scraping.Configuration.Model.Metrics.ResourceTypes;
using Promitor.Core.Scraping.Configuration.Serialization.Core;
using YamlDotNet.RepresentationModel;

namespace Promitor.Core.Scraping.Configuration.Serialization.Deserializers
{
internal class GenericAzureMetricDeserializer : MetricDeserializer
{
/// <summary>Deserializes the specified Generic Azure metric node from the YAML configuration file.</summary>
/// <param name="metricNode">The metric node containing 'filter' and 'resourceUri' parameters pointing to an arbitrary Azure resource</param>
/// <returns>A new <see cref="MetricDefinition"/> object (strongly typed as a <see cref="GenericAzureMetricDefinition"/>) </returns>
internal override MetricDefinition Deserialize(YamlMappingNode metricNode)
{
var metricDefinition = base.DeserializeMetricDefinition<GenericAzureMetricDefinition>(metricNode);

if (metricNode.Children.TryGetValue(new YamlScalarNode("filter"), out var filterNode))
{
metricDefinition.Filter = filterNode?.ToString();
}

var resourceUri = metricNode.Children[new YamlScalarNode("resourceUri")];

metricDefinition.ResourceUri = resourceUri?.ToString();

return metricDefinition;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Promitor.Core.Scraping.Configuration.Model.Metrics;
using Promitor.Core.Scraping.Configuration.Model.Metrics.ResourceTypes;
using YamlDotNet.RepresentationModel;

namespace Promitor.Core.Scraping.Configuration.Serialization.Deserializers
{
internal class ServiceBusQueueMetricDeserializer : GenericAzureMetricDeserializer
{
/// <summary>Deserializes the specified Service Bus Queue metric node from the YAML configuration file.</summary>
/// <param name="metricNode">The metric node containing 'queueName' and 'namespace' parameters pointing to an instance of a Service Bus queue</param>
/// <returns>A new <see cref="MetricDefinition"/> object (strongly typed as a <see cref="ServiceBusQueueMetricDefinition"/>) </returns>
internal override MetricDefinition Deserialize(YamlMappingNode metricNode)
{
var metricDefinition = base.DeserializeMetricDefinition<ServiceBusQueueMetricDefinition>(metricNode);

var queueName = metricNode.Children[new YamlScalarNode("queueName")];
var namespaceName = metricNode.Children[new YamlScalarNode("namespace")];

metricDefinition.QueueName = queueName?.ToString();
metricDefinition.Namespace = namespaceName?.ToString();

return metricDefinition;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Promitor.Core.Scraping.Configuration.Model.Metrics;
using Promitor.Core.Scraping.Configuration.Model.Metrics.ResourceTypes;
using YamlDotNet.RepresentationModel;

namespace Promitor.Core.Scraping.Configuration.Serialization.Deserializers
{
internal class StorageQueueMetricDeserializer : GenericAzureMetricDeserializer
{
/// <summary>Deserializes the specified Storage Queue metric node from the YAML configuration file.</summary>
/// <param name="metricNode">The metric node containing 'accountName', 'queueName', and 'sasToken' parameters pointing to an instance of a Storage queue</param>
/// <returns>A new <see cref="MetricDefinition"/> object (strongly typed as a <see cref="StorageQueueMetricDefinition"/>) </returns>
internal override MetricDefinition Deserialize(YamlMappingNode metricNode)
{
var metricDefinition = base.DeserializeMetricDefinition<StorageQueueMetricDefinition>(metricNode);
var accountName = metricNode.Children[new YamlScalarNode("accountName")];
var queueName = metricNode.Children[new YamlScalarNode("queueName")];
var sasToken = metricNode.Children[new YamlScalarNode("sasToken")];

metricDefinition.AccountName = accountName?.ToString();
metricDefinition.QueueName = queueName?.ToString();
metricDefinition.SasToken = sasToken?.ToString();

return metricDefinition;
}
}
}
Loading

0 comments on commit 2c72d10

Please sign in to comment.