diff --git a/src/Seq.Api/Client/SeqApiClient.cs b/src/Seq.Api/Client/SeqApiClient.cs
index f0b690b..295467b 100644
--- a/src/Seq.Api/Client/SeqApiClient.cs
+++ b/src/Seq.Api/Client/SeqApiClient.cs
@@ -59,7 +59,7 @@ public sealed class SeqApiClient : IDisposable
/// The base URL of the Seq server.
/// An API key to use when making requests to the server, if required.
/// Whether default credentials will be sent with HTTP requests; the default is true.
- [Obsolete("Prefer `SeqApiClient(serverUrl, apiKey, handler => handler.UseDefaultCredentials = true)` instead."), EditorBrowsable(EditorBrowsableState.Never)]
+ [Obsolete("Prefer `SeqApiClient(serverUrl, apiKey, createHttpMessageHandler)` instead."), EditorBrowsable(EditorBrowsableState.Never)]
public SeqApiClient(string serverUrl, string apiKey, bool useDefaultCredentials)
: this(serverUrl, apiKey, handler => handler.UseDefaultCredentials = useDefaultCredentials)
{
@@ -72,25 +72,45 @@ public SeqApiClient(string serverUrl, string apiKey, bool useDefaultCredentials)
/// An API key to use when making requests to the server, if required.
/// An optional callback to configure the used when making HTTP requests
/// to the Seq API.
- public SeqApiClient(string serverUrl, string apiKey = null, Action configureHttpClientHandler = null)
+ [Obsolete("Prefer `SeqApiClient(serverUrl, apiKey, createHttpMessageHandler)` instead."), EditorBrowsable(EditorBrowsableState.Never)]
+ public SeqApiClient(string serverUrl, string apiKey, Action configureHttpClientHandler)
+ : this(serverUrl, apiKey, cookies =>
+ {
+ var handler = new HttpClientHandler { CookieContainer = cookies };
+ configureHttpClientHandler?.Invoke(handler);
+ return handler;
+ })
+ {
+ }
+
+ ///
+ /// Construct a .
+ ///
+ /// The base URL of the Seq server.
+ /// An API key to use when making requests to the server, if required.
+ /// An optional callback to construct the HTTP message handler used when making requests
+ /// to the Seq API. The callback receives a that is shared with WebSocket requests made by the client.
+ public SeqApiClient(string serverUrl, string apiKey = null, Func createHttpMessageHandler = null)
{
+ // This is required for compatibility with the obsolete constructor, which we can remove sometime in 2024.
+ var httpMessageHandler = createHttpMessageHandler?.Invoke(_cookies) ??
+#if SOCKETS_HTTP_HANDLER
+ new SocketsHttpHandler { CookieContainer = _cookies };
+#else
+ new HttpClientHandler { CookieContainer = _cookies };
+#endif
+
ServerUrl = serverUrl ?? throw new ArgumentNullException(nameof(serverUrl));
if (!string.IsNullOrEmpty(apiKey))
_apiKey = apiKey;
-
- var handler = new HttpClientHandler
- {
- CookieContainer = _cookies
- };
-
- configureHttpClientHandler?.Invoke(handler);
-
+
var baseAddress = serverUrl;
if (!baseAddress.EndsWith("/"))
baseAddress += "/";
- HttpClient = new HttpClient(handler) { BaseAddress = new Uri(baseAddress) };
+ HttpClient = new HttpClient(httpMessageHandler);
+ HttpClient.BaseAddress = new Uri(baseAddress);
HttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(SeqApiV9MediaType));
if (_apiKey != null)
@@ -251,8 +271,8 @@ public async Task PutAsync(ILinked entity, string link, TEntity content
var linkUri = ResolveLink(entity, link, parameters);
var request = new HttpRequestMessage(HttpMethod.Put, linkUri) { Content = MakeJsonContent(content) };
var stream = await HttpSendAsync(request, cancellationToken).ConfigureAwait(false);
- using (var reader = new StreamReader(stream))
- reader.ReadToEnd();
+ using var reader = new StreamReader(stream);
+ await reader.ReadToEndAsync();
}
///
@@ -270,8 +290,8 @@ public async Task DeleteAsync(ILinked entity, string link, TEntity cont
var linkUri = ResolveLink(entity, link, parameters);
var request = new HttpRequestMessage(HttpMethod.Delete, linkUri) { Content = MakeJsonContent(content) };
var stream = await HttpSendAsync(request, cancellationToken).ConfigureAwait(false);
- using (var reader = new StreamReader(stream))
- reader.ReadToEnd();
+ using var reader = new StreamReader(stream);
+ await reader.ReadToEndAsync();
}
///
@@ -345,8 +365,8 @@ async Task HttpGetStringAsync(string url, CancellationToken cancellation
{
var request = new HttpRequestMessage(HttpMethod.Get, url);
var stream = await HttpSendAsync(request, cancellationToken).ConfigureAwait(false);
- using (var reader = new StreamReader(stream))
- return await reader.ReadToEndAsync();
+ using var reader = new StreamReader(stream);
+ return await reader.ReadToEndAsync().ConfigureAwait(false);
}
async Task HttpSendAsync(HttpRequestMessage request, CancellationToken cancellationToken = default)
diff --git a/src/Seq.Api/Model/Alerting/AlertOccurrencePart.cs b/src/Seq.Api/Model/Alerting/AlertOccurrencePart.cs
index c5fed8b..7adfa5a 100644
--- a/src/Seq.Api/Model/Alerting/AlertOccurrencePart.cs
+++ b/src/Seq.Api/Model/Alerting/AlertOccurrencePart.cs
@@ -19,7 +19,7 @@ public class AlertOccurrencePart
///
/// The time grouping that triggered the alert.
///
- public DateTimeRange DetectedOverRange { get; set; }
+ public DateTimeRangePart DetectedOverRange { get; set; }
///
/// The level of notifications sent for this instance.
diff --git a/src/Seq.Api/Model/Alerting/AlertOccurrenceRangePart.cs b/src/Seq.Api/Model/Alerting/AlertOccurrenceRangePart.cs
index bd2df84..7a9116c 100644
--- a/src/Seq.Api/Model/Alerting/AlertOccurrenceRangePart.cs
+++ b/src/Seq.Api/Model/Alerting/AlertOccurrenceRangePart.cs
@@ -11,6 +11,6 @@ public class AlertOccurrenceRangePart
///
/// The time grouping that triggered the alert.
///
- public DateTimeRange DetectedOverRange { get; set; }
+ public DateTimeRangePart DetectedOverRange { get; set; }
}
}
diff --git a/src/Seq.Api/Model/Cluster/ClusterNodeEntity.cs b/src/Seq.Api/Model/Cluster/ClusterNodeEntity.cs
index f8056e5..db17fa3 100644
--- a/src/Seq.Api/Model/Cluster/ClusterNodeEntity.cs
+++ b/src/Seq.Api/Model/Cluster/ClusterNodeEntity.cs
@@ -43,6 +43,21 @@ public class ClusterNodeEntity : Entity
/// The time since the node's last completed sync operation.
///
public double? MillisecondsSinceLastSync { get; set; }
+
+ ///
+ /// The time since the follower's active sync was started.
+ ///
+ public double? MillisecondsSinceActiveSync { get; set; }
+
+ ///
+ /// The total number of operations in the active sync.
+ ///
+ public int? TotalActiveOps { get; set; }
+
+ ///
+ /// The remaining number of operations in the active sync.
+ ///
+ public int? RemainingActiveOps { get; set; }
///
/// An informational description of the node's current state, or null if no additional
diff --git a/src/Seq.Api/Model/Diagnostics/Storage/StorageConsumptionPart.cs b/src/Seq.Api/Model/Diagnostics/Storage/StorageConsumptionPart.cs
index 3ca6df3..437f9dd 100644
--- a/src/Seq.Api/Model/Diagnostics/Storage/StorageConsumptionPart.cs
+++ b/src/Seq.Api/Model/Diagnostics/Storage/StorageConsumptionPart.cs
@@ -25,12 +25,12 @@ public class StorageConsumptionPart
///
/// The range of timestamps covered by the result.
///
- public DateTimeRange Range { get; set; }
+ public DateTimeRangePart Range { get; set; }
///
/// The available range of timestamps.
///
- public DateTimeRange FullRange { get; set; }
+ public DateTimeRangePart FullRange { get; set; }
///
/// The duration of the timestamp interval covered by each result.
diff --git a/src/Seq.Api/Model/Events/EventEntity.cs b/src/Seq.Api/Model/Events/EventEntity.cs
index fb38bad..fa58cca 100644
--- a/src/Seq.Api/Model/Events/EventEntity.cs
+++ b/src/Seq.Api/Model/Events/EventEntity.cs
@@ -62,5 +62,24 @@ public class EventEntity : Entity
///
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string RenderedMessage { get; set; }
+
+ ///
+ /// A trace id associated with the event, if any.
+ ///
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public string TraceId { get; set; }
+
+ ///
+ /// A span id associated with the event, if any.
+ ///
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public string SpanId { get; set; }
+
+ ///
+ /// A collection of properties describing the origin of the event, if any. These correspond to resource
+ /// attributes in the OpenTelemetry spec.
+ ///
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public List Resource { get; set; }
}
}
diff --git a/src/Seq.Api/Model/Shared/DateTimeRange.cs b/src/Seq.Api/Model/Shared/DateTimeRange.cs
index 8790bdc..ee5a43f 100644
--- a/src/Seq.Api/Model/Shared/DateTimeRange.cs
+++ b/src/Seq.Api/Model/Shared/DateTimeRange.cs
@@ -5,7 +5,7 @@ namespace Seq.Api.Model.Shared
///
/// A range represented by a start and end .
///
- public readonly struct DateTimeRange
+ public readonly struct DateTimeRangePart
{
///
/// The (inclusive) start of the range.
@@ -18,11 +18,11 @@ public readonly struct DateTimeRange
public DateTime End { get; }
///
- /// Construct a .
+ /// Construct a .
///
/// The (inclusive) start of the range.
/// The (exclusive) end of the range.
- public DateTimeRange(DateTime start, DateTime end)
+ public DateTimeRangePart(DateTime start, DateTime end)
{
Start = start;
End = end;
diff --git a/src/Seq.Api/ResourceGroups/ApiKeysResourceGroup.cs b/src/Seq.Api/ResourceGroups/ApiKeysResourceGroup.cs
index ad98137..c6fbe1d 100644
--- a/src/Seq.Api/ResourceGroups/ApiKeysResourceGroup.cs
+++ b/src/Seq.Api/ResourceGroups/ApiKeysResourceGroup.cs
@@ -121,5 +121,17 @@ public async Task GetMeasurementTimeseriesAsync(ApiKe
var parameters = new Dictionary{ ["id"] = entity.Id, ["measurement"] = measurement };
return await GroupGetAsync("Metric", parameters, cancellationToken);
}
+
+ ///
+ /// Retrieve a detailed metric for all API keys.
+ ///
+ /// A allowing the operation to be canceled.
+ /// The measurement to get.
+ ///
+ public async Task> GetAllMeasurementTimeseriesAsync(string measurement, CancellationToken cancellationToken = default)
+ {
+ var parameters = new Dictionary{ ["measurement"] = measurement };
+ return await GroupGetAsync>("Metrics", parameters, cancellationToken);
+ }
}
}
diff --git a/src/Seq.Api/Seq.Api.csproj b/src/Seq.Api/Seq.Api.csproj
index a43ff62..27c4c1a 100644
--- a/src/Seq.Api/Seq.Api.csproj
+++ b/src/Seq.Api/Seq.Api.csproj
@@ -1,7 +1,7 @@
Client library for the Seq HTTP API.
- 2023.3.1
+ 2023.1.2
Datalust;Contributors
netstandard2.0;net6.0
true
@@ -14,6 +14,10 @@
9
+
+ $(DefineConstants);SOCKETS_HTTP_HANDLER
+
+
diff --git a/src/Seq.Api/SeqConnection.cs b/src/Seq.Api/SeqConnection.cs
index 63703ce..35df2ce 100644
--- a/src/Seq.Api/SeqConnection.cs
+++ b/src/Seq.Api/SeqConnection.cs
@@ -41,7 +41,7 @@ public class SeqConnection : ILoadResourceGroup, IDisposable
/// The base URL of the Seq server.
/// An API key to use when making requests to the server, if required.
/// Whether default credentials will be sent with HTTP requests; the default is true.
- [Obsolete("Prefer `SeqConnection(serverUrl, apiKey, handler => handler.UseDefaultCredentials = true)` instead."), EditorBrowsable(EditorBrowsableState.Never)]
+ [Obsolete("Prefer `SeqConnection(serverUrl, apiKey, createHttpMessageHandler)` instead."), EditorBrowsable(EditorBrowsableState.Never)]
public SeqConnection(string serverUrl, string apiKey, bool useDefaultCredentials)
{
if (serverUrl == null) throw new ArgumentNullException(nameof(serverUrl));
@@ -55,11 +55,25 @@ public SeqConnection(string serverUrl, string apiKey, bool useDefaultCredentials
/// An API key to use when making requests to the server, if required.
/// An optional callback to configure the used when making HTTP requests
/// to the Seq API.
- public SeqConnection(string serverUrl, string apiKey = null, Action configureHttpClientHandler = null)
+ [Obsolete("Prefer `SeqConnection(serverUrl, apiKey, createHttpMessageHandler)` instead."), EditorBrowsable(EditorBrowsableState.Never)]
+ public SeqConnection(string serverUrl, string apiKey, Action configureHttpClientHandler)
{
if (serverUrl == null) throw new ArgumentNullException(nameof(serverUrl));
Client = new SeqApiClient(serverUrl, apiKey, configureHttpClientHandler);
}
+
+ ///
+ /// Construct a .
+ ///
+ /// The base URL of the Seq server.
+ /// An API key to use when making requests to the server, if required.
+ /// An optional callback to construct the HTTP message handler used when making requests
+ /// to the Seq API. The callback receives a that is shared with WebSocket requests made by the client.
+ public SeqConnection(string serverUrl, string apiKey = null, Func createHttpMessageHandler = null)
+ {
+ if (serverUrl == null) throw new ArgumentNullException(nameof(serverUrl));
+ Client = new SeqApiClient(serverUrl, apiKey, createHttpMessageHandler);
+ }
///
///