Added DNS analytics methods

This commit is contained in:
2025-10-28 21:07:45 +01:00
parent 69816d0c02
commit 6eed338ea8
12 changed files with 960 additions and 76 deletions

View File

@@ -0,0 +1,42 @@
using System.Threading;
using System.Threading.Tasks;
namespace AMWD.Net.Api.Cloudflare.Dns
{
/// <summary>
/// Extensions for <see href="https://developers.cloudflare.com/api/resources/dns/subresources/analytics/">DNS Analytics</see>.
/// </summary>
public static class DnsAnalyticsExtensions
{
/// <summary>
/// Retrieves a list of summarised aggregate metrics over a given time period.
/// </summary>
/// <remarks>
/// See <see href="https://developers.cloudflare.com/dns/reference/analytics-api-properties/">Analytics API properties</see> for detailed information about the available query parameters.
/// </remarks>
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
/// <param name="zoneId">The zone identifier.</param>
/// <param name="options">Filter options (optional).</param>
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
public static Task<CloudflareResponse<DnsAnalyticsReport>> GetDnsAnalyticsReport(this ICloudflareClient client, string zoneId, GetDnsAnalyticsReportFilter? options = null, CancellationToken cancellationToken = default)
{
zoneId.ValidateCloudflareId();
return client.GetAsync<DnsAnalyticsReport>($"/zones/{zoneId}/dns_analytics/report", options, cancellationToken);
}
/// <summary>
/// Retrieves a list of aggregate metrics grouped by time interval.
/// </summary>
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
/// <param name="zoneId">The zone identifier.</param>
/// <param name="options">Filter options (optional).</param>
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
public static Task<CloudflareResponse<DnsAnalyticsByTime>> GetDnsAnalyticsByTime(this ICloudflareClient client, string zoneId, GetDnsAnalyticsByTimeFilter? options = null, CancellationToken cancellationToken = default)
{
zoneId.ValidateCloudflareId();
return client.GetAsync<DnsAnalyticsByTime>($"/zones/{zoneId}/dns_analytics/report/bytime", options, cancellationToken);
}
}
}

View File

@@ -0,0 +1,73 @@
using System.Runtime.Serialization;
using Newtonsoft.Json.Converters;
namespace AMWD.Net.Api.Cloudflare.Dns
{
/// <summary>
/// Time delta units.
/// <see href="https://github.com/cloudflare/cloudflare-typescript/blob/v4.4.1/src/resources/dns/dns.ts#L103">Source</see>
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum TimeDeltaUnit
{
/// <summary>
/// All time.
/// </summary>
[EnumMember(Value = "all")]
All = 1,
/// <summary>
/// Auto.
/// </summary>
[EnumMember(Value = "auto")]
Auto = 2,
/// <summary>
/// Year.
/// </summary>
[EnumMember(Value = "year")]
Year = 3,
/// <summary>
/// Quarter (3 months).
/// </summary>
[EnumMember(Value = "quarter")]
Quarter = 4,
/// <summary>
/// Month.
/// </summary>
[EnumMember(Value = "month")]
Month = 5,
/// <summary>
/// Week.
/// </summary>
[EnumMember(Value = "week")]
Week = 6,
/// <summary>
/// Day.
/// </summary>
[EnumMember(Value = "day")]
Day = 7,
/// <summary>
/// Hour.
/// </summary>
[EnumMember(Value = "hour")]
Hour = 8,
/// <summary>
/// Dekaminute (10 minutes).
/// </summary>
[EnumMember(Value = "dekaminute")]
DekaMinute = 9,
/// <summary>
/// Minute.
/// </summary>
[EnumMember(Value = "minute")]
Minute = 10
}
}

View File

@@ -0,0 +1,26 @@
using System.Linq;
namespace AMWD.Net.Api.Cloudflare.Dns
{
/// <summary>
/// Filter for DNS analytics report by time.
/// </summary>
public class GetDnsAnalyticsByTimeFilter : GetDnsAnalyticsReportFilter
{
/// <summary>
/// Unit of time to group data by
/// </summary>
public TimeDeltaUnit? TimeDelta { get; set; }
/// <inheritdoc/>
public override IReadOnlyDictionary<string, string> GetQueryParameters()
{
var dict = base.GetQueryParameters().ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
if (TimeDelta.HasValue && Enum.IsDefined(typeof(TimeDeltaUnit), TimeDelta))
dict.Add("time_delta", TimeDelta.Value.GetEnumMemberValue()!);
return dict;
}
}
}

View File

@@ -0,0 +1,78 @@
namespace AMWD.Net.Api.Cloudflare.Dns
{
/// <summary>
/// Filter for DNS analytics report.
/// </summary>
public class GetDnsAnalyticsReportFilter : IQueryParameterFilter
{
/// <summary>
/// A (comma-separated) list of dimensions to group results by.
/// </summary>
/// <remarks>
/// Further see: <see href="https://developers.cloudflare.com/dns/reference/analytics-api-properties/#dimensions">Cloudflare Docs</see>.
/// </remarks>
public IReadOnlyCollection<string>? Dimensions { get; set; }
/// <summary>
/// Segmentation filter in 'attribute operator value' format.
/// </summary>
/// <remarks>
/// Further see: <see href="https://developers.cloudflare.com/dns/reference/analytics-api-properties/#filters">Cloudflare Docs</see>.
/// </remarks>
public string? Filters { get; set; }
/// <summary>
/// Limit number of returned metrics. (Default: 100.000)
/// </summary>
public int? Limit { get; set; }
/// <summary>
/// A (comma-separated) list of metrics to query.
/// </summary>
public IReadOnlyCollection<string>? Metrics { get; set; }
/// <summary>
/// Start date and time of requesting data period in ISO 8601 format.
/// </summary>
public DateTime? Since { get; set; }
/// <summary>
/// A (comma-separated) list of dimensions to sort by, where each dimension may be prefixed by - (descending) or + (ascending)
/// </summary>
public IReadOnlyCollection<string>? Sort { get; set; }
/// <summary>
/// End date and time of requesting data period in ISO 8601 format.
/// </summary>
public DateTime? Until { get; set; }
/// <inheritdoc/>
public virtual IReadOnlyDictionary<string, string> GetQueryParameters()
{
var dict = new Dictionary<string, string>();
if (Dimensions?.Count > 0)
dict.Add("dimensions", string.Join(",", Dimensions));
if (!string.IsNullOrWhiteSpace(Filters))
dict.Add("filters", Filters!.Trim());
if (Limit.HasValue && Limit > 0)
dict.Add("limit", Limit.Value.ToString());
if (Metrics?.Count > 0)
dict.Add("metrics", string.Join(",", Metrics));
if (Since.HasValue)
dict.Add("since", Since.Value.ToIso8601Format());
if (Sort?.Count > 0)
dict.Add("sort", string.Join(",", Sort));
if (Until.HasValue)
dict.Add("until", Until.Value.ToIso8601Format());
return dict;
}
}
}

View File

@@ -1,9 +1,9 @@
using System.Runtime.Serialization;
using Newtonsoft.Json.Converters;
namespace AMWD.Net.Api.Cloudflare.Dns
namespace AMWD.Net.Api.Cloudflare.Dns
{
internal class DNSAnalyticsQuery
/// <summary>
/// The DNS Analytics query.
/// </summary>
public class DnsAnalyticsQuery
{
/// <summary>
/// Array of dimension names.
@@ -35,6 +35,9 @@ namespace AMWD.Net.Api.Cloudflare.Dns
[JsonProperty("time_delta")]
public TimeDeltaUnit? TimeDelta { get; set; }
/// <summary>
/// End date and time of requesting data period.
/// </summary>
[JsonProperty("until")]
public DateTime? Until { get; set; }
@@ -51,72 +54,4 @@ namespace AMWD.Net.Api.Cloudflare.Dns
[JsonProperty("sort")]
public IReadOnlyCollection<string>? Sort { get; set; }
}
/// <summary>
/// Time delta units.
/// <see href="https://github.com/cloudflare/cloudflare-typescript/blob/v4.4.1/src/resources/dns/dns.ts#L103">Source</see>
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum TimeDeltaUnit
{
/// <summary>
/// All time.
/// </summary>
[EnumMember(Value = "all")]
All = 1,
/// <summary>
/// Auto.
/// </summary>
[EnumMember(Value = "auto")]
Auto = 2,
/// <summary>
/// Year.
/// </summary>
[EnumMember(Value = "year")]
Year = 3,
/// <summary>
/// Quarter.
/// </summary>
[EnumMember(Value = "quarter")]
Quarter = 4,
/// <summary>
/// Month.
/// </summary>
[EnumMember(Value = "month")]
Month = 5,
/// <summary>
/// Week.
/// </summary>
[EnumMember(Value = "week")]
Week = 6,
/// <summary>
/// Day.
/// </summary>
[EnumMember(Value = "day")]
Day = 7,
/// <summary>
/// Hour.
/// </summary>
[EnumMember(Value = "hour")]
Hour = 8,
/// <summary>
/// Dekaminute.
/// </summary>
[EnumMember(Value = "dekaminute")]
DekaMinute = 9,
/// <summary>
/// Minute.
/// </summary>
[EnumMember(Value = "minute")]
Minute = 10
}
}

View File

@@ -0,0 +1,77 @@
namespace AMWD.Net.Api.Cloudflare.Dns
{
/// <summary>
/// Summarised aggregate metrics over a given time period as report.
/// </summary>
public class DnsAnalyticsByTime
{
/// <summary>
/// Array with one row per combination of dimension values.
/// </summary>
[JsonProperty("data")]
public IReadOnlyCollection<DnsAnalyticsByTimeData>? Data { get; set; }
/// <summary>
/// Number of seconds between current time and last processed event, in another words how many seconds of data could be missing.
/// </summary>
[JsonProperty("data_lag")]
public int? DataLag { get; set; }
/// <summary>
/// Maximum results for each metric (object mapping metric names to values).
/// Currently always an empty object.
/// </summary>
[JsonProperty("max")]
public object? Max { get; set; }
/// <summary>
/// Minimum results for each metric (object mapping metric names to values).
/// Currently always an empty object.
/// </summary>
[JsonProperty("min")]
public object? Min { get; set; }
/// <summary>
/// The query information.
/// </summary>
[JsonProperty("query")]
public DnsAnalyticsQuery? Query { get; set; }
/// <summary>
/// Total number of rows in the result.
/// </summary>
[JsonProperty("rows")]
public int? Rows { get; set; }
/// <summary>
/// Array of time intervals in the response data. Each interval is represented as an
/// array containing two values: the start time, and the end time.
/// </summary>
[JsonProperty("time_intervals")]
public IReadOnlyCollection<IReadOnlyCollection<string>>? TimeIntervals { get; set; }
/// <summary>
/// Total results for metrics across all data (object mapping metric names to values).
/// </summary>
[JsonProperty("totals")]
public object? Totals { get; set; }
}
/// <summary>
/// A combination of dimension values.
/// </summary>
public class DnsAnalyticsByTimeData
{
/// <summary>
/// Array of dimension values, representing the combination of dimension values corresponding to this row.
/// </summary>
[JsonProperty("dimensions")]
public IReadOnlyCollection<string>? Dimensions { get; set; }
/// <summary>
/// Array with one item per requested metric. Each item is an array of values, broken down by time interval.
/// </summary>
[JsonProperty("metrics")]
public IReadOnlyCollection<IReadOnlyCollection<object>>? Metrics { get; set; }
}
}

View File

@@ -0,0 +1,118 @@
namespace AMWD.Net.Api.Cloudflare.Dns
{
/// <summary>
/// Summarised aggregate metrics over a given time period as report.
/// </summary>
public class DnsAnalyticsReport
{
/// <summary>
/// Array with one row per combination of dimension values.
/// </summary>
[JsonProperty("data")]
public IReadOnlyCollection<DnsAnalyticsReportData>? Data { get; set; }
/// <summary>
/// Number of seconds between current time and last processed event, in another words how many seconds of data could be missing.
/// </summary>
[JsonProperty("data_lag")]
public int? DataLag { get; set; }
/// <summary>
/// Maximum results for each metric (object mapping metric names to values).
/// Currently always an empty object.
/// </summary>
[JsonProperty("max")]
public object? Max { get; set; }
/// <summary>
/// Minimum results for each metric (object mapping metric names to values).
/// Currently always an empty object.
/// </summary>
[JsonProperty("min")]
public object? Min { get; set; }
/// <summary>
/// The query information.
/// </summary>
[JsonProperty("query")]
public DnsAnalyticsReportQuery? Query { get; set; }
/// <summary>
/// Total number of rows in the result.
/// </summary>
[JsonProperty("rows")]
public int? Rows { get; set; }
/// <summary>
/// Total results for metrics across all data (object mapping metric names to values).
/// </summary>
[JsonProperty("totals")]
public object? Totals { get; set; }
}
/// <summary>
/// A combination of dimension values.
/// </summary>
public class DnsAnalyticsReportData
{
/// <summary>
/// Array of dimension values, representing the combination of dimension values corresponding to this row.
/// </summary>
[JsonProperty("dimensions")]
public IReadOnlyCollection<string>? Dimensions { get; set; }
/// <summary>
/// Array with one item per requested metric. Each item is a single value.
/// </summary>
[JsonProperty("metrics")]
public IReadOnlyCollection<int>? Metrics { get; set; }
}
/// <summary>
/// The query information.
/// </summary>
public class DnsAnalyticsReportQuery
{
/// <summary>
/// Array of dimension names.
/// </summary>
[JsonProperty("dimensions")]
public IReadOnlyCollection<string>? Dimensions { get; set; }
/// <summary>
/// Limit number of returned metrics.
/// </summary>
[JsonProperty("limit")]
public int? Limit { get; set; }
/// <summary>
/// Array of metric names.
/// </summary>
[JsonProperty("metrics")]
public IReadOnlyCollection<string>? Metrics { get; set; }
/// <summary>
/// Start date and time of requesting data period in ISO 8601 format.
/// </summary>
[JsonProperty("since")]
public DateTime? Since { get; set; }
/// <summary>
/// End date and time of requesting data period in ISO 8601 format.
/// </summary>
[JsonProperty("until")]
public DateTime? Until { get; set; }
/// <summary>
/// Segmentation filter in 'attribute operator value' format.
/// </summary>
[JsonProperty("filters")]
public string? Filters { get; set; }
/// <summary>
/// Array of dimension names to sort by, where each dimension may be prefixed by - (descending) or + (ascending).
/// </summary>
[JsonProperty("sort")]
public IReadOnlyCollection<string>? Sort { get; set; }
}
}

View File

@@ -13,7 +13,13 @@ This package contains the feature set of the _DNS_ section of the Cloudflare API
### [DNS]
### [DNSSEC]
#### [Analytics]
- [Get Report Table](https://developers.cloudflare.com/api/resources/dns/subresources/analytics/subresources/reports/methods/get/)
- [Get Report By Time](https://developers.cloudflare.com/api/resources/dns/subresources/analytics/subresources/reports/subresources/bytimes/methods/get/)
#### [DNSSEC]
- [Delete DNSSEC Records](https://developers.cloudflare.com/api/resources/dns/subresources/dnssec/methods/delete/)
- [Edit DNSSEC Status](https://developers.cloudflare.com/api/resources/dns/subresources/dnssec/methods/edit/)
@@ -65,6 +71,7 @@ Published under MIT License (see [choose a license])
[Account Custom Nameservers]: https://developers.cloudflare.com/api/resources/custom_nameservers/
[DNS]: https://developers.cloudflare.com/api/resources/dns/
[Analytics]: https://developers.cloudflare.com/api/resources/dns/subresources/analytics/
[DNSSEC]: https://developers.cloudflare.com/api/resources/dns/subresources/dnssec/
[Records]: https://developers.cloudflare.com/api/resources/dns/subresources/records/
[Settings]: https://developers.cloudflare.com/api/resources/dns/subresources/settings/