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
54 changes: 37 additions & 17 deletions src/Seq.Api/Client/SeqApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public sealed class SeqApiClient : IDisposable
/// <param name="serverUrl">The base URL of the Seq server.</param>
/// <param name="apiKey">An API key to use when making requests to the server, if required.</param>
/// <param name="useDefaultCredentials">Whether default credentials will be sent with HTTP requests; the default is <c>true</c>.</param>
[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)
{
Expand All @@ -72,25 +72,45 @@ public SeqApiClient(string serverUrl, string apiKey, bool useDefaultCredentials)
/// <param name="apiKey">An API key to use when making requests to the server, if required.</param>
/// <param name="configureHttpClientHandler">An optional callback to configure the <see cref="HttpClientHandler"/> used when making HTTP requests
/// to the Seq API.</param>
public SeqApiClient(string serverUrl, string apiKey = null, Action<HttpClientHandler> configureHttpClientHandler = null)
[Obsolete("Prefer `SeqApiClient(serverUrl, apiKey, createHttpMessageHandler)` instead."), EditorBrowsable(EditorBrowsableState.Never)]
public SeqApiClient(string serverUrl, string apiKey, Action<HttpClientHandler> configureHttpClientHandler)
: this(serverUrl, apiKey, cookies =>
{
var handler = new HttpClientHandler { CookieContainer = cookies };
configureHttpClientHandler?.Invoke(handler);
return handler;
})
{
}

/// <summary>
/// Construct a <see cref="SeqApiClient"/>.
/// </summary>
/// <param name="serverUrl">The base URL of the Seq server.</param>
/// <param name="apiKey">An API key to use when making requests to the server, if required.</param>
/// <param name="createHttpMessageHandler">An optional callback to construct the HTTP message handler used when making requests
/// to the Seq API. The callback receives a <see cref="CookieContainer"/> that is shared with WebSocket requests made by the client.</param>
public SeqApiClient(string serverUrl, string apiKey = null, Func<CookieContainer, HttpMessageHandler> 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)
Expand Down Expand Up @@ -251,8 +271,8 @@ public async Task PutAsync<TEntity>(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();
}

/// <summary>
Expand All @@ -270,8 +290,8 @@ public async Task DeleteAsync<TEntity>(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();
}

/// <summary>
Expand Down Expand Up @@ -345,8 +365,8 @@ async Task<string> 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<Stream> HttpSendAsync(HttpRequestMessage request, CancellationToken cancellationToken = default)
Expand Down
2 changes: 1 addition & 1 deletion src/Seq.Api/Model/Alerting/AlertOccurrencePart.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class AlertOccurrencePart
/// <summary>
/// The time grouping that triggered the alert.
/// </summary>
public DateTimeRange DetectedOverRange { get; set; }
public DateTimeRangePart DetectedOverRange { get; set; }

/// <summary>
/// The level of notifications sent for this instance.
Expand Down
2 changes: 1 addition & 1 deletion src/Seq.Api/Model/Alerting/AlertOccurrenceRangePart.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ public class AlertOccurrenceRangePart
/// <summary>
/// The time grouping that triggered the alert.
/// </summary>
public DateTimeRange DetectedOverRange { get; set; }
public DateTimeRangePart DetectedOverRange { get; set; }
}
}
15 changes: 15 additions & 0 deletions src/Seq.Api/Model/Cluster/ClusterNodeEntity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,21 @@ public class ClusterNodeEntity : Entity
/// The time since the node's last completed sync operation.
/// </summary>
public double? MillisecondsSinceLastSync { get; set; }

/// <summary>
/// The time since the follower's active sync was started.
/// </summary>
public double? MillisecondsSinceActiveSync { get; set; }

/// <summary>
/// The total number of operations in the active sync.
/// </summary>
public int? TotalActiveOps { get; set; }

/// <summary>
/// The remaining number of operations in the active sync.
/// </summary>
public int? RemainingActiveOps { get; set; }

/// <summary>
/// An informational description of the node's current state, or <c langword="null">null</c> if no additional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ public class StorageConsumptionPart
/// <summary>
/// The range of timestamps covered by the result.
/// </summary>
public DateTimeRange Range { get; set; }
public DateTimeRangePart Range { get; set; }

/// <summary>
/// The available range of timestamps.
/// </summary>
public DateTimeRange FullRange { get; set; }
public DateTimeRangePart FullRange { get; set; }

/// <summary>
/// The duration of the timestamp interval covered by each result.
Expand Down
19 changes: 19 additions & 0 deletions src/Seq.Api/Model/Events/EventEntity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,24 @@ public class EventEntity : Entity
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string RenderedMessage { get; set; }

/// <summary>
/// A trace id associated with the event, if any.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string TraceId { get; set; }

/// <summary>
/// A span id associated with the event, if any.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string SpanId { get; set; }

/// <summary>
/// A collection of properties describing the origin of the event, if any. These correspond to resource
/// attributes in the OpenTelemetry spec.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public List<EventPropertyPart> Resource { get; set; }
}
}
6 changes: 3 additions & 3 deletions src/Seq.Api/Model/Shared/DateTimeRange.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Seq.Api.Model.Shared
/// <summary>
/// A range represented by a start and end <see cref="DateTime"/>.
/// </summary>
public readonly struct DateTimeRange
public readonly struct DateTimeRangePart
{
/// <summary>
/// The (inclusive) start of the range.
Expand All @@ -18,11 +18,11 @@ public readonly struct DateTimeRange
public DateTime End { get; }

/// <summary>
/// Construct a <see cref="DateTimeRange"/>.
/// Construct a <see cref="DateTimeRangePart"/>.
/// </summary>
/// <param name="start">The (inclusive) start of the range.</param>
/// <param name="end">The (exclusive) end of the range.</param>
public DateTimeRange(DateTime start, DateTime end)
public DateTimeRangePart(DateTime start, DateTime end)
{
Start = start;
End = end;
Expand Down
12 changes: 12 additions & 0 deletions src/Seq.Api/ResourceGroups/ApiKeysResourceGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,5 +121,17 @@ public async Task<MeasurementTimeseriesPart> GetMeasurementTimeseriesAsync(ApiKe
var parameters = new Dictionary<string, object>{ ["id"] = entity.Id, ["measurement"] = measurement };
return await GroupGetAsync<MeasurementTimeseriesPart>("Metric", parameters, cancellationToken);
}

/// <summary>
/// Retrieve a detailed metric for all API keys.
/// </summary>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> allowing the operation to be canceled.</param>
/// <param name="measurement">The measurement to get.</param>
/// <returns></returns>
public async Task<Dictionary<string, MeasurementTimeseriesPart>> GetAllMeasurementTimeseriesAsync(string measurement, CancellationToken cancellationToken = default)
{
var parameters = new Dictionary<string, object>{ ["measurement"] = measurement };
return await GroupGetAsync<Dictionary<string, MeasurementTimeseriesPart>>("Metrics", parameters, cancellationToken);
}
}
}
6 changes: 5 additions & 1 deletion src/Seq.Api/Seq.Api.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Client library for the Seq HTTP API.</Description>
<VersionPrefix>2023.3.1</VersionPrefix>
<VersionPrefix>2023.1.2</VersionPrefix>
<Authors>Datalust;Contributors</Authors>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
Expand All @@ -14,6 +14,10 @@
<LangVersion>9</LangVersion>
</PropertyGroup>

<PropertyGroup Condition=" '$(TargetFramework)' == 'net6.0' ">
<DefineConstants>$(DefineConstants);SOCKETS_HTTP_HANDLER</DefineConstants>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Tavis.UriTemplates" Version="2.0.0" />
Expand Down
18 changes: 16 additions & 2 deletions src/Seq.Api/SeqConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public class SeqConnection : ILoadResourceGroup, IDisposable
/// <param name="serverUrl">The base URL of the Seq server.</param>
/// <param name="apiKey">An API key to use when making requests to the server, if required.</param>
/// <param name="useDefaultCredentials">Whether default credentials will be sent with HTTP requests; the default is <c>true</c>.</param>
[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));
Expand All @@ -55,11 +55,25 @@ public SeqConnection(string serverUrl, string apiKey, bool useDefaultCredentials
/// <param name="apiKey">An API key to use when making requests to the server, if required.</param>
/// <param name="configureHttpClientHandler">An optional callback to configure the <see cref="HttpClientHandler"/> used when making HTTP requests
/// to the Seq API.</param>
public SeqConnection(string serverUrl, string apiKey = null, Action<HttpClientHandler> configureHttpClientHandler = null)
[Obsolete("Prefer `SeqConnection(serverUrl, apiKey, createHttpMessageHandler)` instead."), EditorBrowsable(EditorBrowsableState.Never)]
public SeqConnection(string serverUrl, string apiKey, Action<HttpClientHandler> configureHttpClientHandler)
{
if (serverUrl == null) throw new ArgumentNullException(nameof(serverUrl));
Client = new SeqApiClient(serverUrl, apiKey, configureHttpClientHandler);
}

/// <summary>
/// Construct a <see cref="SeqConnection"/>.
/// </summary>
/// <param name="serverUrl">The base URL of the Seq server.</param>
/// <param name="apiKey">An API key to use when making requests to the server, if required.</param>
/// <param name="createHttpMessageHandler">An optional callback to construct the HTTP message handler used when making requests
/// to the Seq API. The callback receives a <see cref="CookieContainer"/> that is shared with WebSocket requests made by the client.</param>
public SeqConnection(string serverUrl, string apiKey = null, Func<CookieContainer, HttpMessageHandler> createHttpMessageHandler = null)
{
if (serverUrl == null) throw new ArgumentNullException(nameof(serverUrl));
Client = new SeqApiClient(serverUrl, apiKey, createHttpMessageHandler);
}

/// <summary>
/// <inheritdoc/>
Expand Down