Skip to content

Commit 7de6f6a

Browse files
authored
Merge pull request #144 from datalust/dev
2025.2.0 Release
2 parents 95a41c8 + b64c0b0 commit 7de6f6a

File tree

5 files changed

+138
-162
lines changed

5 files changed

+138
-162
lines changed

README.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ Seq internally limits the resources a query is allowed to consume. The query met
5252
The snippet below demonstrates lazily enumerating through results to retrieve the complete set.
5353

5454
```csharp
55-
var resultSet = await connection.Events.EnumerateAsync(
55+
var resultSet = connection.Events.EnumerateAsync(
5656
filter: "Environment = 'Test'",
5757
render: true,
5858
count: 1000);
@@ -65,20 +65,19 @@ All methods that retrieve events require a `count`. The API client defaults this
6565

6666
### Streaming events
6767

68-
Seq 3.4 provides live streaming of events matching a filter and/or set of signals.
68+
Seq provides live streaming of events matching a filter and/or set of signals.
6969

7070
```csharp
7171
var filter = "@Level = 'Error'";
7272

73-
using (var stream = await connection.Events.StreamAsync<JObject>(filter: filter))
74-
using (stream.Select(jObject => LogEventReader.ReadFromJObject(jObject))
75-
.Subscribe(evt => Log.Write(evt)))
73+
await foreach (var evt in connection.Events.StreamAsync<JObject>(filter: filter, clef: true))
7674
{
77-
await stream;
75+
var logEvent = LogEventReader.ReadFromString(evt);
76+
Log.Write(logEvent);
7877
}
7978
```
8079

81-
The `Events.StreamAsync()` method returns a hot `IObservable<T>` over a _WebSocket_. The observable will keep producing events until either it's disposed, or the server is shut down.
80+
`Events.StreamAsync()` method returns `IAsyncEnumerable<T>` over a _WebSocket_. The enumerator will keep producing events until either it's disposed, or the server is shut down.
8281

8382
Seq streams the events in [compact JSON format](https://github.com/serilog/serilog-formatting-compact), which the Seq API client library can deserialize into JSON.NET `JObjects` for consumption.
8483

src/Seq.Api/Client/SeqApiClient.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public sealed class SeqApiClient : IDisposable
4242
// Future versions of Seq may not completely support vN-1 features, however
4343
// providing this as an Accept header will ensure what compatibility is available
4444
// can be utilized.
45-
const string SeqApiV11MediaType = "application/vnd.datalust.seq.v11+json";
45+
const string SeqApiV11MediaType = "application/vnd.datalust.seq.v12+json";
4646

4747
// ReSharper disable once NotAccessedField.Local
4848
readonly bool _defaultMessageHandler;

src/Seq.Api/Model/AppInstances/AppInstanceEntity.cs

Lines changed: 127 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -19,160 +19,139 @@
1919
using Seq.Api.Model.Inputs;
2020
using Seq.Api.Model.Signals;
2121
using Seq.Api.ResourceGroups;
22+
// ReSharper disable UnusedAutoPropertyAccessor.Global
2223

2324
#nullable enable
2425

25-
namespace Seq.Api.Model.AppInstances
26+
namespace Seq.Api.Model.AppInstances;
27+
28+
/// <summary>
29+
/// App instances are individual processes based on a running <see cref="AppEntity"/> that can
30+
/// read from and write to the Seq event stream.
31+
/// </summary>
32+
public class AppInstanceEntity : Entity
2633
{
2734
/// <summary>
28-
/// App instances are individual processes based on a running <see cref="AppEntity"/> that can
29-
/// read from and write to the Seq event stream.
35+
/// Construct an <see cref="AppInstanceEntity"/> with default values.
3036
/// </summary>
31-
public class AppInstanceEntity : Entity
37+
/// <remarks>Instead of constructing an instance directly, consider using
38+
/// <see cref="AppInstancesResourceGroup.TemplateAsync"/> to obtain a partly-initialized instance.</remarks>
39+
public AppInstanceEntity()
3240
{
33-
/// <summary>
34-
/// Construct an <see cref="AppInstanceEntity"/> with default values.
35-
/// </summary>
36-
/// <remarks>Instead of constructing an instance directly, consider using
37-
/// <see cref="AppInstancesResourceGroup.TemplateAsync"/> to obtain a partly-initialized instance.</remarks>
38-
public AppInstanceEntity()
39-
{
40-
Settings = new Dictionary<string, string>();
41-
InvocationOverridableSettings = new List<string>();
42-
InvocationOverridableSettingDefinitions = new List<AppSettingPart>();
43-
EventsPerSuppressionWindow = 1;
44-
ProcessMetrics = new AppInstanceProcessMetricsPart();
45-
InputSettings = new InputSettingsPart();
46-
InputMetrics = new InputMetricsPart();
47-
DiagnosticInputMetrics = new InputMetricsPart();
48-
OutputMetrics = new AppInstanceOutputMetricsPart();
49-
}
50-
51-
/// <summary>
52-
/// The id of the <see cref="AppEntity"/> that this is an instance of.
53-
/// </summary>
54-
public string? AppId { get; set; }
55-
56-
/// <summary>
57-
/// The user-friendly title of the app instance.
58-
/// </summary>
59-
public string? Title { get; set; }
60-
61-
/// <summary>
62-
/// Values for the settings exposed by the app.
63-
/// </summary>
64-
public Dictionary<string, string>? Settings { get; set; }
65-
66-
/// <summary>
67-
/// If <c>true</c>, administrative users may invoke the app manually or through alerts.
68-
/// This field is read-only from the API and generally indicates that the app is an input.
69-
/// </summary>
70-
public bool AcceptPrivilegedInvocation { get; set; }
71-
72-
/// <summary>
73-
/// If <c>true</c>, regular users can manually send events to the app, or use the app
74-
/// as the target for alert notifications.
75-
/// </summary>
76-
public bool AcceptDirectInvocation { get; set; }
77-
78-
/// <summary>
79-
/// The settings that can be overridden at invocation time (when an event is sent to
80-
/// the instance).
81-
/// </summary>
82-
public List<string>? InvocationOverridableSettings { get; set; }
83-
84-
/// <summary>
85-
/// Metadata describing the overridable settings. This field is provided by the server
86-
/// and cannot be modified.
87-
/// </summary>
88-
public List<AppSettingPart>? InvocationOverridableSettingDefinitions { get; set; }
89-
90-
/// <summary>
91-
/// If <c>true</c>, events will be streamed to the app. Otherwise, events will be
92-
/// sent only manually or in response to alerts being triggered.
93-
/// </summary>
94-
public bool AcceptStreamedEvents { get; set; }
95-
96-
/// <summary>
97-
/// The signal expression describing which events will be sent to the app; if <c>null</c>,
98-
/// all events will reach the app.
99-
/// </summary>
100-
public SignalExpressionPart? StreamedSignalExpression { get; set; }
101-
102-
/// <summary>
103-
/// If a value is specified, events will be buffered to disk and sorted by timestamp-order
104-
/// within the specified window. This is not recommended for performance reasons, and should
105-
/// be avoided when possible.
106-
/// </summary>
107-
public TimeSpan? ArrivalWindow { get; set; }
108-
109-
/// <summary>
110-
/// The time after an event reaches the app during which no further events will be processed.
111-
/// The default <see cref="TimeSpan.Zero"/> indicates no suppression time, and all events
112-
/// will be processed in that case.
113-
/// </summary>
114-
public TimeSpan SuppressionTime { get; set; }
115-
116-
/// <summary>
117-
/// If <see cref="SuppressionTime"/> is set, the number of events that will be allowed during the
118-
/// suppression window. The default is <c>1</c>, to allow only the initial event that triggered suppression.
119-
/// </summary>
120-
public int EventsPerSuppressionWindow { get; set; }
121-
122-
/// <summary>
123-
/// Settings that control how events are ingested through the app.
124-
/// </summary>
125-
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
126-
public InputSettingsPart? InputSettings { get; set; }
127-
128-
/// <summary>
129-
/// Metrics describing the state and activity of the app process.
130-
/// </summary>
131-
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
132-
public AppInstanceProcessMetricsPart? ProcessMetrics { get; set; }
133-
134-
/// <summary>
135-
/// Information about ingestion activity through this app.
136-
/// </summary>
137-
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
138-
public InputMetricsPart? InputMetrics { get; set; }
139-
140-
/// <summary>
141-
/// Information about the app's diagnostic input.
142-
/// </summary>
143-
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
144-
public InputMetricsPart? DiagnosticInputMetrics { get; set; }
145-
146-
/// <summary>
147-
/// Information about events output through the app.
148-
/// </summary>
149-
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
150-
public AppInstanceOutputMetricsPart? OutputMetrics { get; set; }
151-
152-
/// <summary>
153-
/// Obsolete.
154-
/// </summary>
155-
[Obsolete("Use !AcceptStreamedEvents instead.")]
156-
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
157-
public bool? IsManualInputOnly { get; set; }
158-
159-
/// <summary>
160-
/// Obsolete.
161-
/// </summary>
162-
[Obsolete("Use !AcceptDirectInvocation instead.")]
163-
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
164-
public bool? DisallowManualInput { get; set; }
165-
166-
/// <summary>
167-
/// The name of the app.
168-
/// </summary>
169-
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
170-
public string? AppName { get; set; }
171-
172-
/// <summary>
173-
/// If <c>true</c>, then the app is able to write events to the log.
174-
/// </summary>
175-
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
176-
public bool? IsInput { get; set; }
41+
Settings = new Dictionary<string, string>();
42+
InvocationOverridableSettings = new List<string>();
43+
InvocationOverridableSettingDefinitions = new List<AppSettingPart>();
44+
EventsPerSuppressionWindow = 1;
45+
ProcessMetrics = new AppInstanceProcessMetricsPart();
46+
InputSettings = new InputSettingsPart();
47+
InputMetrics = new InputMetricsPart();
48+
DiagnosticInputMetrics = new InputMetricsPart();
49+
OutputMetrics = new AppInstanceOutputMetricsPart();
17750
}
51+
52+
/// <summary>
53+
/// The id of the <see cref="AppEntity"/> that this is an instance of.
54+
/// </summary>
55+
public string? AppId { get; set; }
56+
57+
/// <summary>
58+
/// The user-friendly title of the app instance.
59+
/// </summary>
60+
public string? Title { get; set; }
61+
62+
/// <summary>
63+
/// Values for the settings exposed by the app.
64+
/// </summary>
65+
public Dictionary<string, string>? Settings { get; set; }
66+
67+
/// <summary>
68+
/// If <c>true</c>, administrative users may invoke the app manually or through alerts.
69+
/// This field is read-only from the API and generally indicates that the app is an input.
70+
/// </summary>
71+
public bool AcceptPrivilegedInvocation { get; set; }
72+
73+
/// <summary>
74+
/// If <c>true</c>, regular users can manually send events to the app, or use the app
75+
/// as the target for alert notifications.
76+
/// </summary>
77+
public bool AcceptDirectInvocation { get; set; }
78+
79+
/// <summary>
80+
/// The settings that can be overridden at invocation time (when an event is sent to
81+
/// the instance).
82+
/// </summary>
83+
public List<string>? InvocationOverridableSettings { get; set; }
84+
85+
/// <summary>
86+
/// Metadata describing the overridable settings. This field is provided by the server
87+
/// and cannot be modified.
88+
/// </summary>
89+
public List<AppSettingPart>? InvocationOverridableSettingDefinitions { get; set; }
90+
91+
/// <summary>
92+
/// If <c>true</c>, events will be streamed to the app. Otherwise, events will be
93+
/// sent only manually or in response to alerts being triggered.
94+
/// </summary>
95+
public bool AcceptStreamedEvents { get; set; }
96+
97+
/// <summary>
98+
/// The signal expression describing which events will be sent to the app; if <c>null</c>,
99+
/// all events will reach the app.
100+
/// </summary>
101+
public SignalExpressionPart? StreamedSignalExpression { get; set; }
102+
103+
/// <summary>
104+
/// The time after an event reaches the app during which no further events will be processed.
105+
/// The default <see cref="TimeSpan.Zero"/> indicates no suppression time, and all events
106+
/// will be processed in that case.
107+
/// </summary>
108+
public TimeSpan SuppressionTime { get; set; }
109+
110+
/// <summary>
111+
/// If <see cref="SuppressionTime"/> is set, the number of events that will be allowed during the
112+
/// suppression window. The default is <c>1</c>, to allow only the initial event that triggered suppression.
113+
/// </summary>
114+
public int EventsPerSuppressionWindow { get; set; }
115+
116+
/// <summary>
117+
/// Settings that control how events are ingested through the app.
118+
/// </summary>
119+
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
120+
public InputSettingsPart? InputSettings { get; set; }
121+
122+
/// <summary>
123+
/// Metrics describing the state and activity of the app process.
124+
/// </summary>
125+
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
126+
public AppInstanceProcessMetricsPart? ProcessMetrics { get; set; }
127+
128+
/// <summary>
129+
/// Information about ingestion activity through this app.
130+
/// </summary>
131+
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
132+
public InputMetricsPart? InputMetrics { get; set; }
133+
134+
/// <summary>
135+
/// Information about the app's diagnostic input.
136+
/// </summary>
137+
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
138+
public InputMetricsPart? DiagnosticInputMetrics { get; set; }
139+
140+
/// <summary>
141+
/// Information about events output through the app.
142+
/// </summary>
143+
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
144+
public AppInstanceOutputMetricsPart? OutputMetrics { get; set; }
145+
146+
/// <summary>
147+
/// The name of the app.
148+
/// </summary>
149+
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
150+
public string? AppName { get; set; }
151+
152+
/// <summary>
153+
/// If <c>true</c>, then the app is able to write events to the log.
154+
/// </summary>
155+
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
156+
public bool? IsInput { get; set; }
178157
}

src/Seq.Api/ResourceGroups/AppInstancesResourceGroup.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,12 @@ public async Task<AppInstanceEntity> TemplateAsync(string appId, CancellationTok
7272
/// Add a new app instance.
7373
/// </summary>
7474
/// <param name="entity">The app instance to add.</param>
75-
/// <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
76-
/// for the app, which is not recommended for performance reasons.</param>
7775
/// <param name="cancellationToken">A <see cref="CancellationToken"/> allowing the operation to be canceled.</param>
7876
/// <returns>The app instance, with server-allocated properties such as <see cref="Entity.Id"/> initialized.</returns>
79-
public async Task<AppInstanceEntity> AddAsync(AppInstanceEntity entity, bool runOnExisting = false, CancellationToken cancellationToken = default)
77+
public async Task<AppInstanceEntity> AddAsync(AppInstanceEntity entity, CancellationToken cancellationToken = default)
8078
{
8179
if (entity == null) throw new ArgumentNullException(nameof(entity));
82-
return await GroupCreateAsync<AppInstanceEntity, AppInstanceEntity>(entity, new Dictionary<string, object> { { "runOnExisting", runOnExisting } }, cancellationToken)
80+
return await GroupCreateAsync<AppInstanceEntity, AppInstanceEntity>(entity, cancellationToken: cancellationToken)
8381
.ConfigureAwait(false);
8482
}
8583

src/Seq.Api/Seq.Api.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<Description>Client library for the Seq HTTP API.</Description>
4-
<VersionPrefix>2025.1.0</VersionPrefix>
4+
<VersionPrefix>2025.2.0</VersionPrefix>
55
<Authors>Datalust;Contributors</Authors>
66
<TargetFrameworks>netstandard2.0;net6.0;net8.0</TargetFrameworks>
77
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
@@ -28,7 +28,7 @@
2828
</ItemGroup>
2929

3030
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0'">
31-
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.4" />
31+
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.5" />
3232
<PackageReference Include="Nullable" Version="1.3.1" PrivateAssets="all">
3333
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
3434
</PackageReference>

0 commit comments

Comments
 (0)