Skip to content

Add Serialization & Deserialization of Sink File Properties with CLI Commands #2752

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

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions schemas/dab.draft.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,40 @@
},
"required": ["endpoint"]
},
"file": {
"type": "object",
"additionalProperties": false,
"properties": {
"enabled": {
"type": "boolean",
"description": "Enable/disable file sink telemetry logging.",
"default": false
},
"path": {
"type": "string",
"description": "File path for telemetry logs.",
"default": "/logs/dab-log.txt"
},
"rolling-interval": {
"type": "string",
"description": "Rolling interval for log files.",
"default": "day",
"enum": ["hour", "day", "week"]
},
"retained-file-count-limit": {
"type": "integer",
"description": "Maximum number of retained log files.",
"default": 1,
"minimum": 1
},
"file-size-limit-bytes": {
"type": "integer",
"description": "Maximum file size in bytes before rolling.",
"default": 1048576,
"minimum": 1
}
}
},
"log-level": {
"type": "object",
"description": "Global configuration of log level, defines logging severity levels for specific classes, when 'null' it will set logging level based on 'host: mode' property",
Expand Down
30 changes: 30 additions & 0 deletions src/Cli/Commands/AddTelemetryOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ public AddTelemetryOptions(
string? openTelemetryHeaders = null,
OtlpExportProtocol? openTelemetryExportProtocol = null,
string? openTelemetryServiceName = null,
CliBool? fileSinkEnabled = null,
string? fileSinkPath = null,
RollingIntervalMode? fileSinkRollingInterval = null,
int? fileSinkRetainedFileCountLimit = null,
int? fileSinkFileSizeLimitBytes = null,
string? config = null) : base(config)
{
AppInsightsConnString = appInsightsConnString;
Expand All @@ -36,6 +41,11 @@ public AddTelemetryOptions(
OpenTelemetryHeaders = openTelemetryHeaders;
OpenTelemetryExportProtocol = openTelemetryExportProtocol;
OpenTelemetryServiceName = openTelemetryServiceName;
FileSinkEnabled = fileSinkEnabled;
FileSinkPath = fileSinkPath;
FileSinkRollingInterval = fileSinkRollingInterval;
FileSinkRetainedFileCountLimit = fileSinkRetainedFileCountLimit;
FileSinkFileSizeLimitBytes = fileSinkFileSizeLimitBytes;
}

// Connection string for the Application Insights resource to which telemetry data should be sent.
Expand Down Expand Up @@ -68,6 +78,26 @@ public AddTelemetryOptions(
[Option("otel-service-name", Default = "dab", Required = false, HelpText = "(Default: dab) Headers for Open Telemetry for telemetry data")]
public string? OpenTelemetryServiceName { get; }

// To specify whether File Sink telemetry should be enabled. This flag is optional and default value is false.
[Option("file-sink-enabled", Default = CliBool.False, Required = false, HelpText = "Enable/disable file sink telemetry logging. Default: false (boolean).")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For any of these properties with defaults, if the default value is being used, but was not supplied by the user, does the property end up writing back out to the config?

public CliBool? FileSinkEnabled { get; }

// Path for the File Sink resource to which telemetry data should be sent. This flag is optional and default value is '/logs/dab-log.txt'.
[Option("file-sink-path", Default = "/logs/dab-log.txt", Required = false, HelpText = "File path for telemetry logs. Default: '/logs/dab-log.txt' (string).")]
public string? FileSinkPath { get; }

// Rolling Interval for the File Sink resource to which telemetry data should be sent. This flag is optional and default value is new interval per Day.
[Option("file-sink-rolling-interval", Default = RollingIntervalMode.Day, Required = false, HelpText = "Rolling interval for log files. Default: Day. Allowed values: Hour, Day, Week.")]
public RollingIntervalMode? FileSinkRollingInterval { get; }

// Retained File Count Limit for the File Sink resource to which telemetry data should be sent. This flag is optional and default value is 1.
[Option("file-sink-retained-file-count-limit", Default = 1, Required = false, HelpText = "Maximum number of retained log files. Default: 1 (integer, minimum: 1).")]
public int? FileSinkRetainedFileCountLimit { get; }

// File Size Limit Bytes for the File Sink resource to which telemetry data should be sent. This flag is optional and default value is 1048576.
[Option("file-sink-file-size-limit-bytes", Default = 1048576, Required = false, HelpText = "Maximum file size in bytes before rolling. Default: 1048576 (integer, minimum: 1).")]
public int? FileSinkFileSizeLimitBytes { get; }

public int Handler(ILogger logger, FileSystemRuntimeConfigLoader loader, IFileSystem fileSystem)
{
logger.LogInformation("{productName} {version}", PRODUCT_NAME, ProductInfo.GetProductVersion());
Expand Down
21 changes: 10 additions & 11 deletions src/Cli/ConfigGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1969,22 +1969,21 @@ public static bool TryAddTelemetry(AddTelemetryOptions options, FileSystemRuntim
ServiceName: options.OpenTelemetryServiceName
);

FileSinkOptions fileSinkOptions = new(
Enabled: options.FileSinkEnabled is CliBool.True ? true : false,
Path: options.FileSinkPath,
RollingInterval: options.FileSinkRollingInterval,
RetainedFileCountLimit: options.FileSinkRetainedFileCountLimit,
FileSizeLimitBytes: options.FileSinkFileSizeLimitBytes
);

runtimeConfig = runtimeConfig with
{
Runtime = runtimeConfig.Runtime with
{
Telemetry = runtimeConfig.Runtime.Telemetry is null
? new TelemetryOptions(ApplicationInsights: applicationInsightsOptions, OpenTelemetry: openTelemetryOptions)
: runtimeConfig.Runtime.Telemetry with { ApplicationInsights = applicationInsightsOptions, OpenTelemetry = openTelemetryOptions }
}
};
runtimeConfig = runtimeConfig with
{
Runtime = runtimeConfig.Runtime with
{
Telemetry = runtimeConfig.Runtime.Telemetry is null
? new TelemetryOptions(ApplicationInsights: applicationInsightsOptions)
: runtimeConfig.Runtime.Telemetry with { ApplicationInsights = applicationInsightsOptions }
? new TelemetryOptions(ApplicationInsights: applicationInsightsOptions, OpenTelemetry: openTelemetryOptions, File: fileSinkOptions)
: runtimeConfig.Runtime.Telemetry with { ApplicationInsights = applicationInsightsOptions, OpenTelemetry = openTelemetryOptions, File = fileSinkOptions }
}
};

Expand Down
25 changes: 25 additions & 0 deletions src/Config/ObjectModel/FileSinkOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

namespace Azure.DataApiBuilder.Config.ObjectModel;

/// <summary>
/// Represents the options for configuring file sink telemetry.
/// </summary>
public record FileSinkOptions(
bool Enabled = false,
string? Path = "/logs/dab-log.txt",
RollingIntervalMode? RollingInterval = RollingIntervalMode.Day,
int? RetainedFileCountLimit = 1,
int? FileSizeLimitBytes = 1048576)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we try to make FileSinkOptions with values below the minimum in the schema, do we end up with an invalid config, or do we error out first?

{
public bool Enabled { get; init; } = Enabled;

public string? Path { get; init; } = Path;

public RollingIntervalMode? RollingInterval { get; init; } = RollingInterval;

public int? RetainedFileCountLimit { get; init; } = RetainedFileCountLimit;

public int? FileSizeLimitBytes { get; init; } = FileSizeLimitBytes;
}
18 changes: 18 additions & 0 deletions src/Config/ObjectModel/FileSinkRollingIntervalMode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.Text.Json.Serialization;

namespace Azure.DataApiBuilder.Config.ObjectModel;

/// <summary>
/// Represents the rolling interval options for file sink.
/// The time it takes between the creation of new files.
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
Copy link
Preview

Copilot AI Jul 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default JsonStringEnumConverter will serialize enum values as "Hour"/"Day"/"Week", but the JSON schema expects lowercase strings ("hour","day","week"). Consider using JsonStringEnumConverter with a camel‐case naming policy (e.g. new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)) or adjust the schema to match.

Suggested change
[JsonConverter(typeof(JsonStringEnumConverter))]
[JsonConverter(typeof(JsonStringEnumConverter), JsonNamingPolicy.CamelCase)]

Copilot uses AI. Check for mistakes.

public enum RollingIntervalMode
{
Hour,
Day,
Week
}
2 changes: 1 addition & 1 deletion src/Config/ObjectModel/TelemetryOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Azure.DataApiBuilder.Config.ObjectModel;
/// <summary>
/// Represents the options for telemetry.
/// </summary>
public record TelemetryOptions(ApplicationInsightsOptions? ApplicationInsights = null, OpenTelemetryOptions? OpenTelemetry = null, Dictionary<string, LogLevel?>? LoggerLevel = null)
public record TelemetryOptions(ApplicationInsightsOptions? ApplicationInsights = null, OpenTelemetryOptions? OpenTelemetry = null, FileSinkOptions? File = null, Dictionary<string, LogLevel?>? LoggerLevel = null)
{
[JsonPropertyName("log-level")]
public Dictionary<string, LogLevel?>? LoggerLevel { get; init; } = LoggerLevel;
Expand Down