Skip to content
Merged
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
2 changes: 1 addition & 1 deletion src/Seq.Api/Client/SeqApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public sealed class SeqApiClient : IDisposable
// Future versions of Seq may not completely support vN-1 features, however
// providing this as an Accept header will ensure what compatibility is available
// can be utilized.
const string SeqApiV11MediaType = "application/vnd.datalust.seq.v11+json";
const string SeqApiV11MediaType = "application/vnd.datalust.seq.v12+json";

// ReSharper disable once NotAccessedField.Local
readonly bool _defaultMessageHandler;
Expand Down
275 changes: 127 additions & 148 deletions src/Seq.Api/Model/AppInstances/AppInstanceEntity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,160 +19,139 @@
using Seq.Api.Model.Inputs;
using Seq.Api.Model.Signals;
using Seq.Api.ResourceGroups;
// ReSharper disable UnusedAutoPropertyAccessor.Global

#nullable enable

namespace Seq.Api.Model.AppInstances
namespace Seq.Api.Model.AppInstances;

/// <summary>
/// App instances are individual processes based on a running <see cref="AppEntity"/> that can
/// read from and write to the Seq event stream.
/// </summary>
public class AppInstanceEntity : Entity
{
/// <summary>
/// App instances are individual processes based on a running <see cref="AppEntity"/> that can
/// read from and write to the Seq event stream.
/// Construct an <see cref="AppInstanceEntity"/> with default values.
/// </summary>
public class AppInstanceEntity : Entity
/// <remarks>Instead of constructing an instance directly, consider using
/// <see cref="AppInstancesResourceGroup.TemplateAsync"/> to obtain a partly-initialized instance.</remarks>
public AppInstanceEntity()
{
/// <summary>
/// Construct an <see cref="AppInstanceEntity"/> with default values.
/// </summary>
/// <remarks>Instead of constructing an instance directly, consider using
/// <see cref="AppInstancesResourceGroup.TemplateAsync"/> to obtain a partly-initialized instance.</remarks>
public AppInstanceEntity()
{
Settings = new Dictionary<string, string>();
InvocationOverridableSettings = new List<string>();
InvocationOverridableSettingDefinitions = new List<AppSettingPart>();
EventsPerSuppressionWindow = 1;
ProcessMetrics = new AppInstanceProcessMetricsPart();
InputSettings = new InputSettingsPart();
InputMetrics = new InputMetricsPart();
DiagnosticInputMetrics = new InputMetricsPart();
OutputMetrics = new AppInstanceOutputMetricsPart();
}

/// <summary>
/// The id of the <see cref="AppEntity"/> that this is an instance of.
/// </summary>
public string? AppId { get; set; }

/// <summary>
/// The user-friendly title of the app instance.
/// </summary>
public string? Title { get; set; }

/// <summary>
/// Values for the settings exposed by the app.
/// </summary>
public Dictionary<string, string>? Settings { get; set; }

/// <summary>
/// If <c>true</c>, administrative users may invoke the app manually or through alerts.
/// This field is read-only from the API and generally indicates that the app is an input.
/// </summary>
public bool AcceptPrivilegedInvocation { get; set; }

/// <summary>
/// If <c>true</c>, regular users can manually send events to the app, or use the app
/// as the target for alert notifications.
/// </summary>
public bool AcceptDirectInvocation { get; set; }

/// <summary>
/// The settings that can be overridden at invocation time (when an event is sent to
/// the instance).
/// </summary>
public List<string>? InvocationOverridableSettings { get; set; }

/// <summary>
/// Metadata describing the overridable settings. This field is provided by the server
/// and cannot be modified.
/// </summary>
public List<AppSettingPart>? InvocationOverridableSettingDefinitions { get; set; }

/// <summary>
/// If <c>true</c>, events will be streamed to the app. Otherwise, events will be
/// sent only manually or in response to alerts being triggered.
/// </summary>
public bool AcceptStreamedEvents { get; set; }

/// <summary>
/// The signal expression describing which events will be sent to the app; if <c>null</c>,
/// all events will reach the app.
/// </summary>
public SignalExpressionPart? StreamedSignalExpression { get; set; }

/// <summary>
/// If a value is specified, events will be buffered to disk and sorted by timestamp-order
/// within the specified window. This is not recommended for performance reasons, and should
/// be avoided when possible.
/// </summary>
public TimeSpan? ArrivalWindow { get; set; }

/// <summary>
/// The time after an event reaches the app during which no further events will be processed.
/// The default <see cref="TimeSpan.Zero"/> indicates no suppression time, and all events
/// will be processed in that case.
/// </summary>
public TimeSpan SuppressionTime { get; set; }

/// <summary>
/// If <see cref="SuppressionTime"/> is set, the number of events that will be allowed during the
/// suppression window. The default is <c>1</c>, to allow only the initial event that triggered suppression.
/// </summary>
public int EventsPerSuppressionWindow { get; set; }

/// <summary>
/// Settings that control how events are ingested through the app.
/// </summary>
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public InputSettingsPart? InputSettings { get; set; }

/// <summary>
/// Metrics describing the state and activity of the app process.
/// </summary>
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public AppInstanceProcessMetricsPart? ProcessMetrics { get; set; }

/// <summary>
/// Information about ingestion activity through this app.
/// </summary>
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public InputMetricsPart? InputMetrics { get; set; }

/// <summary>
/// Information about the app's diagnostic input.
/// </summary>
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public InputMetricsPart? DiagnosticInputMetrics { get; set; }

/// <summary>
/// Information about events output through the app.
/// </summary>
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public AppInstanceOutputMetricsPart? OutputMetrics { get; set; }

/// <summary>
/// Obsolete.
/// </summary>
[Obsolete("Use !AcceptStreamedEvents instead.")]
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public bool? IsManualInputOnly { get; set; }

/// <summary>
/// Obsolete.
/// </summary>
[Obsolete("Use !AcceptDirectInvocation instead.")]
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public bool? DisallowManualInput { get; set; }

/// <summary>
/// The name of the app.
/// </summary>
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string? AppName { get; set; }

/// <summary>
/// If <c>true</c>, then the app is able to write events to the log.
/// </summary>
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public bool? IsInput { get; set; }
Settings = new Dictionary<string, string>();
InvocationOverridableSettings = new List<string>();
InvocationOverridableSettingDefinitions = new List<AppSettingPart>();
EventsPerSuppressionWindow = 1;
ProcessMetrics = new AppInstanceProcessMetricsPart();
InputSettings = new InputSettingsPart();
InputMetrics = new InputMetricsPart();
DiagnosticInputMetrics = new InputMetricsPart();
OutputMetrics = new AppInstanceOutputMetricsPart();
}

/// <summary>
/// The id of the <see cref="AppEntity"/> that this is an instance of.
/// </summary>
public string? AppId { get; set; }

/// <summary>
/// The user-friendly title of the app instance.
/// </summary>
public string? Title { get; set; }

/// <summary>
/// Values for the settings exposed by the app.
/// </summary>
public Dictionary<string, string>? Settings { get; set; }

/// <summary>
/// If <c>true</c>, administrative users may invoke the app manually or through alerts.
/// This field is read-only from the API and generally indicates that the app is an input.
/// </summary>
public bool AcceptPrivilegedInvocation { get; set; }

/// <summary>
/// If <c>true</c>, regular users can manually send events to the app, or use the app
/// as the target for alert notifications.
/// </summary>
public bool AcceptDirectInvocation { get; set; }

/// <summary>
/// The settings that can be overridden at invocation time (when an event is sent to
/// the instance).
/// </summary>
public List<string>? InvocationOverridableSettings { get; set; }

/// <summary>
/// Metadata describing the overridable settings. This field is provided by the server
/// and cannot be modified.
/// </summary>
public List<AppSettingPart>? InvocationOverridableSettingDefinitions { get; set; }

/// <summary>
/// If <c>true</c>, events will be streamed to the app. Otherwise, events will be
/// sent only manually or in response to alerts being triggered.
/// </summary>
public bool AcceptStreamedEvents { get; set; }

/// <summary>
/// The signal expression describing which events will be sent to the app; if <c>null</c>,
/// all events will reach the app.
/// </summary>
public SignalExpressionPart? StreamedSignalExpression { get; set; }

/// <summary>
/// The time after an event reaches the app during which no further events will be processed.
/// The default <see cref="TimeSpan.Zero"/> indicates no suppression time, and all events
/// will be processed in that case.
/// </summary>
public TimeSpan SuppressionTime { get; set; }

/// <summary>
/// If <see cref="SuppressionTime"/> is set, the number of events that will be allowed during the
/// suppression window. The default is <c>1</c>, to allow only the initial event that triggered suppression.
/// </summary>
public int EventsPerSuppressionWindow { get; set; }

/// <summary>
/// Settings that control how events are ingested through the app.
/// </summary>
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public InputSettingsPart? InputSettings { get; set; }

/// <summary>
/// Metrics describing the state and activity of the app process.
/// </summary>
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public AppInstanceProcessMetricsPart? ProcessMetrics { get; set; }

/// <summary>
/// Information about ingestion activity through this app.
/// </summary>
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public InputMetricsPart? InputMetrics { get; set; }

/// <summary>
/// Information about the app's diagnostic input.
/// </summary>
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public InputMetricsPart? DiagnosticInputMetrics { get; set; }

/// <summary>
/// Information about events output through the app.
/// </summary>
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public AppInstanceOutputMetricsPart? OutputMetrics { get; set; }

/// <summary>
/// The name of the app.
/// </summary>
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string? AppName { get; set; }

/// <summary>
/// If <c>true</c>, then the app is able to write events to the log.
/// </summary>
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public bool? IsInput { get; set; }
}
6 changes: 2 additions & 4 deletions src/Seq.Api/ResourceGroups/AppInstancesResourceGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,12 @@ public async Task<AppInstanceEntity> TemplateAsync(string appId, CancellationTok
/// Add a new app instance.
/// </summary>
/// <param name="entity">The app instance to add.</param>
/// <param name="runOnExisting">If <c>true</c>, events already on the server will be sent to the app. Note that this requires disk buffering and persistent bookmarks
/// for the app, which is not recommended for performance reasons.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> allowing the operation to be canceled.</param>
/// <returns>The app instance, with server-allocated properties such as <see cref="Entity.Id"/> initialized.</returns>
public async Task<AppInstanceEntity> AddAsync(AppInstanceEntity entity, bool runOnExisting = false, CancellationToken cancellationToken = default)
public async Task<AppInstanceEntity> AddAsync(AppInstanceEntity entity, CancellationToken cancellationToken = default)
{
if (entity == null) throw new ArgumentNullException(nameof(entity));
return await GroupCreateAsync<AppInstanceEntity, AppInstanceEntity>(entity, new Dictionary<string, object> { { "runOnExisting", runOnExisting } }, cancellationToken)
return await GroupCreateAsync<AppInstanceEntity, AppInstanceEntity>(entity, cancellationToken: cancellationToken)
.ConfigureAwait(false);
}

Expand Down
2 changes: 1 addition & 1 deletion src/Seq.Api/Seq.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.4" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.5" />
<PackageReference Include="Nullable" Version="1.3.1" PrivateAssets="all">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down