diff --git a/src/Seq.Api/Client/SeqApiClient.cs b/src/Seq.Api/Client/SeqApiClient.cs index fed86cb..d25ae82 100644 --- a/src/Seq.Api/Client/SeqApiClient.cs +++ b/src/Seq.Api/Client/SeqApiClient.cs @@ -41,7 +41,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 SeqApiVersionedMediaType = "application/vnd.datalust.seq.v13+json"; + const string SeqApiVersionedMediaType = "application/vnd.datalust.seq.v14+json"; const string ApiKeyHeaderName = "X-Seq-ApiKey"; const string CsrfTokenHeaderName = "X-Seq-CsrfToken"; @@ -531,7 +531,7 @@ static string EnsureAbsoluteWebSocketUri(string target, Uri apiBaseAddress) absoluteUnknownScheme.Scheme = absoluteUnknownScheme.Scheme.Equals("http", StringComparison.OrdinalIgnoreCase) || absoluteUnknownScheme.Scheme.Equals("ws", StringComparison.OrdinalIgnoreCase) ? "ws" : "wss"; - + return absoluteUnknownScheme.ToString(); } diff --git a/src/Seq.Api/Model/Dashboarding/ChartQueryPart.cs b/src/Seq.Api/Model/Dashboarding/ChartQueryPart.cs index 2f84f5b..d4d2054 100644 --- a/src/Seq.Api/Model/Dashboarding/ChartQueryPart.cs +++ b/src/Seq.Api/Model/Dashboarding/ChartQueryPart.cs @@ -28,10 +28,20 @@ public class ChartQueryPart /// public string Id { get; set; } + /// + /// The source of the data displayed by the chart. + /// + public DataSource DataSource { get; set; } = DataSource.Stream; + + /// + /// Lateral joins applied to the data source. + /// + public List Joins { get; set; } = []; + /// /// Individual measurements included in the query. These are effectively projected columns. /// - public List Measurements { get; set; } = new List(); + public List Measurements { get; set; } = []; /// /// An optional filtering where clause limiting the data that contributes to the chart. @@ -46,12 +56,12 @@ public class ChartQueryPart /// /// A series of expressions used to group data returned by the query. /// - public List GroupBy { get; set; } = new List(); + public List GroupBy { get; set; } = []; /// /// How measurements included in the chart will be displayed. /// - public MeasurementDisplayStylePart DisplayStyle { get; set; } = new MeasurementDisplayStylePart(); + public MeasurementDisplayStylePart DisplayStyle { get; set; } = new(); /// /// A filter that limits which groups will be displayed on the chart. Not supported by all chart types. @@ -61,7 +71,7 @@ public class ChartQueryPart /// /// An ordering applied to the results of the query; not supported by all chart types. /// - public List OrderBy { get; set; } = new List(); + public List OrderBy { get; set; } = []; /// /// The row limit used for the query. By default, a server-determined limit will be applied. diff --git a/src/Seq.Api/Model/Diagnostics/ColumnStore/ColumnStatisticsPart.cs b/src/Seq.Api/Model/Diagnostics/ColumnStore/ColumnStatisticsPart.cs new file mode 100644 index 0000000..918ec4a --- /dev/null +++ b/src/Seq.Api/Model/Diagnostics/ColumnStore/ColumnStatisticsPart.cs @@ -0,0 +1,45 @@ +// Copyright © Datalust and contributors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +namespace Seq.Api.Model.Diagnostics.ColumnStore; + +/// +/// Describes a particular (column name, encoding) pair. Storage for each column is broken down by encoding because +/// the summary information available for each encoding differs. +/// +public class ColumnStatisticsPart +{ + /// + /// The name of the column. For most user-provided data, such as metrics or labels, the column name will + /// correspond to the metric or label name. Complex objects are decomposed into individual columns per sub-property. + /// Note that these names approximate the Seq query language syntax for referring to the column, but this is + /// inexact. + /// + public string Name { get; set; } + + /// + /// A textual description of the native encoding scheme used for the column data. + /// + public string Encoding { get; set; } + + /// + /// The number of rows in which the column has a defined value. + /// + public long Count { get; set; } + + /// + /// The full on-disk size of the encoded column data, excluding framing details such as CRC blocks, padding, and + /// file layout overhead (these are usually trivial). + /// + public long SizeBytes { get; set; } +} diff --git a/src/Seq.Api/Model/Diagnostics/ColumnStore/ColumnStoreStatisticsPart.cs b/src/Seq.Api/Model/Diagnostics/ColumnStore/ColumnStoreStatisticsPart.cs new file mode 100644 index 0000000..c40240a --- /dev/null +++ b/src/Seq.Api/Model/Diagnostics/ColumnStore/ColumnStoreStatisticsPart.cs @@ -0,0 +1,28 @@ +// Copyright © Datalust and contributors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System.Collections.Generic; + +namespace Seq.Api.Model.Diagnostics.ColumnStore; + +/// +/// Provides information about the internal column store that drives Seq's metrics features. +/// +public class ColumnStoreStatisticsPart +{ + /// + /// The columns stored in the column store. + /// + public List Columns { get; set; } = new(); +} \ No newline at end of file diff --git a/src/Seq.Api/Model/Events/EventEntity.cs b/src/Seq.Api/Model/Events/EventEntity.cs index 5d8a7ab..fbfa96b 100644 --- a/src/Seq.Api/Model/Events/EventEntity.cs +++ b/src/Seq.Api/Model/Events/EventEntity.cs @@ -116,5 +116,11 @@ public class EventEntity : Entity /// [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public TimeSpan? Elapsed { get; set; } + + /// + /// If the event is a metric, the definitions of its metric samples. + /// + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public List Definitions { get; set; } } } diff --git a/src/Seq.Api/Model/Inputs/ApiKeyEntity.cs b/src/Seq.Api/Model/Inputs/ApiKeyEntity.cs index bb0c4a6..bb9b284 100644 --- a/src/Seq.Api/Model/Inputs/ApiKeyEntity.cs +++ b/src/Seq.Api/Model/Inputs/ApiKeyEntity.cs @@ -47,7 +47,7 @@ public class ApiKeyEntity : Entity /// /// Settings that control how events are ingested through the API key. /// - public InputSettingsPart InputSettings { get; set; } = new InputSettingsPart(); + public InputSettingsPart InputSettings { get; set; } = new(); /// /// If true, the key is the built-in (tokenless) API key representing unauthenticated HTTP ingestion. @@ -63,12 +63,12 @@ public class ApiKeyEntity : Entity /// The s assigned to the API key. Note that, if the API key is owned by an individual user, permissions /// not held by the user will be ignored by the server. /// - public HashSet AssignedPermissions { get; set; } = new HashSet(); + public HashSet AssignedPermissions { get; set; } = []; /// /// Information about the ingestion activity using this API key. /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public InputMetricsPart InputMetrics { get; set; } = new InputMetricsPart(); + public InputMetricsPart InputMetrics { get; set; } = new(); } } diff --git a/src/Seq.Api/Model/Inputs/InputSettingsPart.cs b/src/Seq.Api/Model/Inputs/InputSettingsPart.cs index 3eae56d..c0159f3 100644 --- a/src/Seq.Api/Model/Inputs/InputSettingsPart.cs +++ b/src/Seq.Api/Model/Inputs/InputSettingsPart.cs @@ -27,12 +27,12 @@ public class InputSettingsPart /// Properties that will be automatically added to all events ingested using the key. These will override any properties with /// the same names already present on the event. /// - public List AppliedProperties { get; set; } = new List(); + public List AppliedProperties { get; set; } = []; /// /// A filter that selects events to ingest. If null, all events received using the key will be ingested. /// - public DescriptiveFilterPart Filter { get; set; } = new DescriptiveFilterPart(); + public DescriptiveFilterPart Filter { get; set; } = new(); /// /// A minimum level at which events received using the key will be ingested. The level hierarchy understood by Seq is fuzzy diff --git a/src/Seq.Api/Model/Metrics/DimensionFilterOperator.cs b/src/Seq.Api/Model/Metrics/DimensionFilterOperator.cs new file mode 100644 index 0000000..2f5720c --- /dev/null +++ b/src/Seq.Api/Model/Metrics/DimensionFilterOperator.cs @@ -0,0 +1,23 @@ +#nullable enable +namespace Seq.Api.Model.Metrics; + +/// +/// A simplified representation of the expression encoded in a . +/// +public enum DimensionFilterOperator +{ + /// + /// The filter includes samples with for the dimension. + /// + Include, + + /// + /// The filter excludes samples with for the dimension. + /// + Exclude, + + /// + /// The filter includes samples with any value for the dimension. + /// + Has, +} \ No newline at end of file diff --git a/src/Seq.Api/Model/Metrics/DimensionFilterPart.cs b/src/Seq.Api/Model/Metrics/DimensionFilterPart.cs new file mode 100644 index 0000000..37e248f --- /dev/null +++ b/src/Seq.Api/Model/Metrics/DimensionFilterPart.cs @@ -0,0 +1,24 @@ +#nullable enable +namespace Seq.Api.Model.Metrics; + +/// +/// A filter (requirement) applied to a metric dimension. +/// +public class DimensionFilterPart +{ + /// + /// The dimension. See . + /// + public required string Accessor { get; set; } + + /// + /// How the filter applies to the dimension. + /// + public DimensionFilterOperator Operator { get; set; } + + /// + /// When is or + /// , the value included or excluded by the filter. Ignored otherwise. + /// + public object? Value { get; set; } +} \ No newline at end of file diff --git a/src/Seq.Api/Model/Metrics/MetricAggregationPreference.cs b/src/Seq.Api/Model/Metrics/MetricAggregationPreference.cs new file mode 100644 index 0000000..a9e0985 --- /dev/null +++ b/src/Seq.Api/Model/Metrics/MetricAggregationPreference.cs @@ -0,0 +1,32 @@ +namespace Seq.Api.Model.Metrics; + +/// +/// The aggregate function(s) used when aggregating a metric by time interval for display. +/// +public enum MetricAggregationPreference +{ + /// + /// The count() aggregate function. + /// + Count, + + /// + /// The sum() aggregate function. + /// + Sum, + + /// + /// The min() aggregate function. + /// + Min, + + /// + /// The mean() aggregate function. + /// + Mean, + + /// + /// The max() aggregate function. + /// + Max +} \ No newline at end of file diff --git a/src/Seq.Api/Model/Metrics/MetricDimensionPart.cs b/src/Seq.Api/Model/Metrics/MetricDimensionPart.cs new file mode 100644 index 0000000..ed31e44 --- /dev/null +++ b/src/Seq.Api/Model/Metrics/MetricDimensionPart.cs @@ -0,0 +1,43 @@ +// Copyright © Datalust and contributors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using Newtonsoft.Json; + +namespace Seq.Api.Model.Metrics; + +/// +/// A description of a dimension (property/label, scope, or resource attribute) applied to metric samples. +/// +public class MetricDimensionPart +{ + /// + /// The dimension's accessor path, including the namespace, and using indexer syntax to refer to path elements that + /// are not valid identifiers in the Seq query language. This member is guaranteed to contain a syntactically-valid + /// expression that can be used directly in queries without manipulation. + /// + public string Accessor { get; set; } + + /// + /// The dimension's human-readable name, without namespace qualifiers such as @Resource, and potentially + /// including syntactically-invalid elements. Omitted if identical to the value of . + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string Name { get; set; } + + /// + /// The dimension's namespace. Omitted if the namespace is the default @Properties. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string Namespace { get; set; } +} diff --git a/src/Seq.Api/Model/Metrics/MetricPart.cs b/src/Seq.Api/Model/Metrics/MetricPart.cs new file mode 100644 index 0000000..f598895 --- /dev/null +++ b/src/Seq.Api/Model/Metrics/MetricPart.cs @@ -0,0 +1,75 @@ +// Copyright © Datalust and contributors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#nullable enable +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Seq.Api.Model.Metrics; + +/// +/// The definition of a metric present in the server's series metrics store. +/// +/// +/// Because Seq's internal metric store uses a columnar, rather than timeseries, architecture, it does not impose a +/// fixed notion of metric identity. Instead, metric identity can be flexibly defined in the context of a metrics search. +/// A is the result of such a search, and carries the implied metric identity in its combination +/// of , , , and fields. +/// +public class MetricPart +{ + /// + /// The name of the metric, as a property accessor expression, using indexer syntax to refer to path elements that + /// are not valid identifiers in the Seq query language. This member is guaranteed to contain a syntactically-valid + /// expression that can be used directly in queries without manipulation. + /// + public required string Accessor { get; set; } + + /// + /// The metric's human-readable name, without namespace qualifiers such as @Resource, and potentially + /// including syntactically-invalid elements. Omitted if identical to the value of . + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string? Name { get; set; } + + /// + /// The group within which this metric appears. The indexes into the array will correspond to the indexes of + /// the list of group key expressions provided when retrieving the definition. For example, if the definitions + /// are retrieved with ?group=@Resource.service.name,@Scope.name, then the contents of a returned group + /// key might resemble ["users_api", "AspNetCore.Server.Kestrel"]. + /// + public List GroupKey { get; set; } = []; + + /// + /// The type of data this metric records. This will typically be one of either + /// Sum, Gauge, or (exponential) Histogram. + /// + public required string Kind { get; set; } + + /// + /// A user-facing description of the metric, if one is supplied. + /// + public string? Description { get; set; } + + /// + /// The unit of measure for the metric samples, if one is supplied. + /// + public string? Unit { get; set; } + + /// + /// If a filter or groupings were supplied when retrieving this metric, a where-clause compatible expression + /// that restricts queries for metric data to only the samples matched in the filter, or belonging to the group. + /// + public string? Condition { get; set; } +} diff --git a/src/Seq.Api/Model/Metrics/MetricSearchResultPart.cs b/src/Seq.Api/Model/Metrics/MetricSearchResultPart.cs new file mode 100644 index 0000000..e2f0aae --- /dev/null +++ b/src/Seq.Api/Model/Metrics/MetricSearchResultPart.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + +#nullable enable + +namespace Seq.Api.Model.Metrics; + +/// +/// The result of a metric search. +/// +public class MetricSearchResultPart +{ + /// + /// The metrics matched by the search. + /// + public List Metrics { get; set; } = []; + + /// + /// The subset of each included metric's not derived + /// from , if any. Note that this does not + /// need to be included when retrieving samples for the metric: this field is supplied so that additional queries + /// can be generated utilizing the same data condition in the way already facilitated for groupings by + /// the property. + /// + public string? NonGroupingCondition { get; set; } +} \ No newline at end of file diff --git a/src/Seq.Api/Model/Metrics/StandaloneMetricPart.cs b/src/Seq.Api/Model/Metrics/StandaloneMetricPart.cs new file mode 100644 index 0000000..1868182 --- /dev/null +++ b/src/Seq.Api/Model/Metrics/StandaloneMetricPart.cs @@ -0,0 +1,73 @@ +#nullable enable +using System.Collections.Generic; +using Newtonsoft.Json; +using Seq.Api.Model.Shared; + +namespace Seq.Api.Model.Metrics; + +/// +/// A captured for computation and display outside the context of the original search result in +/// which it appears. +/// +public class StandaloneMetricPart +{ + /// + /// The metric. + /// + public required MetricPart Metric { get; set; } + + /// + /// The expressions used to compute the metric's values. The + /// and values are combined with + /// in the metric's . + /// + /// + /// When an ephemeral metric search result is pinned, the group keys and conditions used when retrieving it + /// are "frozen", and attached to the pinned metric. + /// + public List GroupKeyExpressions { get; set; } = []; + + /// + /// The non-grouping portion of . The + /// and values are combined with + /// in the metric's . + /// + /// + /// When an ephemeral metric search result is pinned, the group keys and conditions used when retrieving it + /// are "frozen", and attached to the pinned metric. + /// + public string? NonGroupingCondition { get; set; } + + /// + /// When displaying the metric, whether the y-axis should use logarithmic tick intervals. If , + /// the y-axis ticks will be at intervals (linear). + /// + public bool UseLogarithmicScale { get; set; } + + /// + /// When displaying the metric, whether the y-axis should begin from zero. If , the y-axis + /// will begin at the value of the smallest data point. + /// + public bool ShowZero { get; set; } = true; + + /// + /// When displaying the metric, the aggregate function(s) used when aggregating a metric by time interval. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public MetricAggregationPreference? AggregationPreference { get; set; } + + /// + /// When displaying the metric, additional filters applied to the underlying data. + /// + public List DisplayExpressionFilters { get; set; } = []; + + /// + /// When displaying the metric, additional keys used to create on-chart group series. + /// + public List DisplayGroupKeyExpressions { get; set; } = []; + + /// + /// When displaying the metric, additional dimension-based filters applied to the underlying data. + /// + public List DisplayDimensionFilters { get; set; } = []; +} \ No newline at end of file diff --git a/src/Seq.Api/Model/Metrics/ViewEntity.cs b/src/Seq.Api/Model/Metrics/ViewEntity.cs new file mode 100644 index 0000000..1c3e014 --- /dev/null +++ b/src/Seq.Api/Model/Metrics/ViewEntity.cs @@ -0,0 +1,61 @@ +#nullable enable +using System.Collections.Generic; +using Seq.Api.Model.Security; +using Seq.Api.Model.Shared; + +namespace Seq.Api.Model.Metrics; + +/// +/// A saved view in the Seq Metrics screen. +/// +public class ViewEntity: Entity +{ + /// + /// Construct a . + /// + public ViewEntity() + { + Title = "New View"; + } + + /// + /// The friendly, human-readable title of the view. + /// + public string Title { get; set; } + + /// + /// A long-form description of the view's purpose and contents. + /// + public string? Description { get; set; } + + /// + /// The user id of the user who owns the view; if null, the view is shared. + /// + public string? OwnerId { get; set; } + + /// + /// If true, the view can only be modified by users with the permission. + /// + public bool IsProtected { get; set; } + + /// + /// One or more expressions (normally, dimension accessor expressions such as @Scope.name) around which + /// metrics are split into separate charts. + /// + public List GroupKeyExpressions { get; set; } = []; + + /// + /// Expressions used to restrict the underlying metric data considered by the view. + /// + public List Filters { get; set; } = []; + + /// + /// Per-dimension filters used to restrict the underlying metric data considered by the view. + /// + public List DimensionFilters { get; set; } = []; + + /// + /// Individual metrics pinned in the view. + /// + public List PinnedMetrics { get; set; } = []; +} \ No newline at end of file diff --git a/src/Seq.Api/Model/Retention/RetentionPolicyEntity.cs b/src/Seq.Api/Model/Retention/RetentionPolicyEntity.cs index 380f850..5efb028 100644 --- a/src/Seq.Api/Model/Retention/RetentionPolicyEntity.cs +++ b/src/Seq.Api/Model/Retention/RetentionPolicyEntity.cs @@ -14,33 +14,38 @@ using System; using Newtonsoft.Json; +using Seq.Api.Model.Shared; using Seq.Api.Model.Signals; -namespace Seq.Api.Model.Retention +namespace Seq.Api.Model.Retention; + +/// +/// A retention policy. Identifies a subset of events to delete at a specified age. +/// +public class RetentionPolicyEntity : Entity { /// - /// A retention policy. Identifies a subset of events to delete at a specified age. + /// The age at which events will be deleted by the policy. This is based on the + /// events' timestamps relative to the server's clock. + /// + public TimeSpan RetentionTime { get; set; } + + /// + /// An optional describing the set of events + /// to delete. If null, the policy will efficiently truncate the event store, + /// deleting all events. Supported only when is . /// - public class RetentionPolicyEntity : Entity - { - /// - /// The age at which events will be deleted by the policy. This is based on the - /// events' timestamps relative to the server's clock. - /// - public TimeSpan RetentionTime { get; set; } + public SignalExpressionPart RemovedSignalExpression { get; set; } - /// - /// An optional describing the set of events - /// to delete. If null, the policy will efficiently truncate the event store, - /// deleting all events. - /// - public SignalExpressionPart RemovedSignalExpression { get; set; } + /// + /// The data source to delete from. If unspecified, defaults to + /// + public DataSource DataSource { get; set; } = DataSource.Stream; - /// - /// Obsolete. - /// - [Obsolete("Replaced by RemovedSignalExpression."), - JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string SignalId { get; set; } - } -} + /// + /// Obsolete. + /// + [Obsolete("Replaced by RemovedSignalExpression."), + JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string SignalId { get; set; } +} \ No newline at end of file diff --git a/src/Seq.Api/Model/Settings/SettingName.cs b/src/Seq.Api/Model/Settings/SettingName.cs index bca9984..3fc11d4 100644 --- a/src/Seq.Api/Model/Settings/SettingName.cs +++ b/src/Seq.Api/Model/Settings/SettingName.cs @@ -165,6 +165,12 @@ public enum SettingName /// NewUserShowDashboardIds, + /// + /// A comma-separated list of (shared) metrics view ids that will be included in any new user's + /// personal default workspace. + /// + NewUserShowViewIds, + /// /// If using OpenID Connect authentication, the URL of the authorization endpoint. For example, /// https://example.com. diff --git a/src/Seq.Api/Model/Shared/CrossJoinLateralPart.cs b/src/Seq.Api/Model/Shared/CrossJoinLateralPart.cs new file mode 100644 index 0000000..efe3f33 --- /dev/null +++ b/src/Seq.Api/Model/Shared/CrossJoinLateralPart.cs @@ -0,0 +1,31 @@ +// Copyright © Datalust and contributors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Seq.Api.Model.Shared; + +/// +/// The lateral cross join part of a from clause. +/// +public class CrossJoinLateralPart +{ + /// + /// The set function call used in the lateral join. + /// + public string SetFunctionCall { get; set; } + + /// + /// The alias of the set function call. + /// + public string Alias { get; set; } +} \ No newline at end of file diff --git a/src/Seq.Api/Model/Shared/DataSource.cs b/src/Seq.Api/Model/Shared/DataSource.cs new file mode 100644 index 0000000..e21dd66 --- /dev/null +++ b/src/Seq.Api/Model/Shared/DataSource.cs @@ -0,0 +1,33 @@ +// Copyright © Datalust and contributors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Seq.Api.Model.Shared; + +/// +/// Identifies the storage objects present in Seq's underlying telemetry database. +/// +public enum DataSource +{ + /// + /// The stream object, which stores log events and trace spans. The stream object is implemented + /// over row-oriented storage, optimized for general search and row-by-row retrieval. + /// + Stream, + + /// + /// The series object, which stores metrics. The series object is implemented over columnar storage, + /// optimized for aggregate queries that each touch a small number of columns. + /// + Series, +} \ No newline at end of file diff --git a/src/Seq.Api/Model/Shared/DescriptiveFilterPart.cs b/src/Seq.Api/Model/Shared/DescriptiveFilterPart.cs index 05761de..c4fd012 100644 --- a/src/Seq.Api/Model/Shared/DescriptiveFilterPart.cs +++ b/src/Seq.Api/Model/Shared/DescriptiveFilterPart.cs @@ -36,7 +36,7 @@ public class DescriptiveFilterPart public string Filter { get; set; } /// - /// The original ("fuzzy") text entered by the user into the filter bar when + /// Optionally, the original ("fuzzy") text entered by the user into the filter bar when /// creating the filter. This may not be syntactically valid, e.g. it may be /// interpreted as free text - hence while it's displayed in the UI and forms the /// basis of user editing of the filter, the value is executed. diff --git a/src/Seq.Api/Model/Signals/SignalEntity.cs b/src/Seq.Api/Model/Signals/SignalEntity.cs index 82fd86d..1b882a8 100644 --- a/src/Seq.Api/Model/Signals/SignalEntity.cs +++ b/src/Seq.Api/Model/Signals/SignalEntity.cs @@ -31,12 +31,12 @@ public class SignalEntity : Entity public SignalEntity() { Title = "New Signal"; - Filters = new List(); - Columns = new List(); + Filters = []; + Columns = []; } /// - /// The friendly, human readable title of the signal. + /// The friendly, human-readable title of the signal. /// public string Title { get; set; } @@ -46,7 +46,7 @@ public SignalEntity() public string Description { get; set; } /// - /// Filters that are combined (using the and operator) to identify events matching the filter. + /// Filters that are combined (using the and operator) to identify events present in the signal. /// public List Filters { get; set; } diff --git a/src/Seq.Api/Model/Workspaces/WorkspaceContentPart.cs b/src/Seq.Api/Model/Workspaces/WorkspaceContentPart.cs index e3c635f..b6924fd 100644 --- a/src/Seq.Api/Model/Workspaces/WorkspaceContentPart.cs +++ b/src/Seq.Api/Model/Workspaces/WorkspaceContentPart.cs @@ -14,6 +14,7 @@ using System.Collections.Generic; using Seq.Api.Model.Dashboarding; +using Seq.Api.Model.Metrics; using Seq.Api.Model.Signals; using Seq.Api.Model.SqlQueries; @@ -27,16 +28,21 @@ public class WorkspaceContentPart /// /// A list of ids to include in the workspace. /// - public List SignalIds { get; set; } = new List(); + public List SignalIds { get; set; } = []; /// /// A list of ids to include in the workspace. /// - public List QueryIds { get; set; } = new List(); + public List QueryIds { get; set; } = []; /// /// A list of ids to include in the workspace. /// - public List DashboardIds { get; set; } = new List(); + public List DashboardIds { get; set; } = []; + + /// + /// A list of ids to include in the workspace. + /// + public List ViewIds { get; set; } = []; } } \ No newline at end of file diff --git a/src/Seq.Api/ResourceGroups/DashboardsResourceGroup.cs b/src/Seq.Api/ResourceGroups/DashboardsResourceGroup.cs index 18d71be..ed9c6ce 100644 --- a/src/Seq.Api/ResourceGroups/DashboardsResourceGroup.cs +++ b/src/Seq.Api/ResourceGroups/DashboardsResourceGroup.cs @@ -36,12 +36,13 @@ internal DashboardsResourceGroup(ILoadResourceGroup connection) /// Retrieve the dashboard with the given id; throws if the entity does not exist. /// /// The id of the dashboard. + /// If true, include only partial details in the result. /// A allowing the operation to be canceled. /// The dashboard. - public async Task FindAsync(string id, CancellationToken cancellationToken = default) + public async Task FindAsync(string id, bool partial = false, CancellationToken cancellationToken = default) { if (id == null) throw new ArgumentNullException(nameof(id)); - return await GroupGetAsync("Item", new Dictionary { { "id", id } }, cancellationToken).ConfigureAwait(false); + return await GroupGetAsync("Item", new Dictionary { { "id", id }, { "partial", partial } }, cancellationToken).ConfigureAwait(false); } /// @@ -50,11 +51,12 @@ public async Task FindAsync(string id, CancellationToken cancel /// If the id of a is provided, only dashboards owned by them will be included in the result; if /// not specified, personal dashboards for all owners will be listed. /// If true, shared dashboards will be included in the result. + /// If true, include only partial details in the result. /// allowing the operation to be canceled. /// A list containing matching dashboards. - public async Task> ListAsync(string ownerId = null, bool shared = false, CancellationToken cancellationToken = default) + public async Task> ListAsync(string ownerId = null, bool shared = false, bool partial = false, CancellationToken cancellationToken = default) { - var parameters = new Dictionary { { "ownerId", ownerId }, { "shared", shared } }; + var parameters = new Dictionary { { "ownerId", ownerId }, { "shared", shared }, { "partial", partial } }; return await GroupListAsync("Items", parameters, cancellationToken).ConfigureAwait(false); } diff --git a/src/Seq.Api/ResourceGroups/EventsResourceGroup.cs b/src/Seq.Api/ResourceGroups/EventsResourceGroup.cs index 514e552..31ee28e 100644 --- a/src/Seq.Api/ResourceGroups/EventsResourceGroup.cs +++ b/src/Seq.Api/ResourceGroups/EventsResourceGroup.cs @@ -70,7 +70,7 @@ public async Task FindAsync( /// created but not saved, a signal from another server, or the modified representation of an entity already persisted. /// If provided, a signal expression describing the set of events that will be filtered for the result. /// A strict Seq filter expression to match (text expressions must be in double quotes). To - /// convert a "fuzzy" filter into a strict one the way the Seq UI does, use connection.Expressions.ToStrictAsync(). + /// convert a "fuzzy" filter into a strict one the way the Seq UI does, use . /// The number of events to retrieve. If not specified will default to 30. /// An event id from which to start searching (inclusively). /// An event id to search after (exclusively). @@ -141,7 +141,7 @@ public async IAsyncEnumerable EnumerateAsync( /// created but not saved, a signal from another server, or the modified representation of an entity already persisted. /// If provided, a signal expression describing the set of events that will be filtered for the result. /// A strict Seq filter expression to match (text expressions must be in double quotes). To - /// convert a "fuzzy" filter into a strict one the way the Seq UI does, use connection.Expressions.ToStrictAsync(). + /// convert a "fuzzy" filter into a strict one the way the Seq UI does, use . /// The number of events to retrieve. If not specified will default to 30. /// An event id from which to start searching (inclusively). /// An event id to search after (exclusively). @@ -220,7 +220,7 @@ public async IAsyncEnumerable PagedEnumerateAsync( /// created but not saved, a signal from another server, or the modified representation of an entity already persisted. /// If provided, a signal expression describing the set of events that will be filtered for the result. /// A strict Seq filter expression to match (text expressions must be in double quotes). To - /// convert a "fuzzy" filter into a strict one the way the Seq UI does, use connection.Expressions.ToStrictAsync(). + /// convert a "fuzzy" filter into a strict one the way the Seq UI does, use . /// The number of events to retrieve. If not specified will default to 30. /// An event id from which to start searching (inclusively). /// An event id to search after (exclusively). @@ -267,7 +267,7 @@ public async Task> ListAsync( /// created but not saved, a signal from another server, or the modified representation of an entity already persisted. /// If provided, a signal expression describing the set of events that will be filtered for the result. /// A strict Seq filter expression to match (text expressions must be in double quotes). To - /// convert a "fuzzy" filter into a strict one the way the Seq UI does, use connection.Expressions.ToStrictAsync(). + /// convert a "fuzzy" filter into a strict one the way the Seq UI does, use . /// The number of events to retrieve. If not specified will default to 30. /// An event id from which to start searching (inclusively). /// An event id to search after (exclusively). @@ -327,7 +327,7 @@ public async Task PageAsync( /// created but not saved, a signal from another server, or the modified representation of an entity already persisted. /// If provided, a signal expression describing the set of events that will be filtered for the result. /// A strict Seq filter expression to match (text expressions must be in double quotes). To - /// convert a "fuzzy" filter into a strict one the way the Seq UI does, use connection.Expressions.ToStrictAsync(). + /// convert a "fuzzy" filter into a strict one the way the Seq UI does, use . /// Earliest (inclusive) date/time from which to delete. /// Latest (exclusive) date/time from which to delete. /// Values for any free variables that appear in . @@ -359,7 +359,7 @@ public async Task DeleteAsync( /// created but not saved, a signal from another server, or the modified representation of an entity already persisted. /// If provided, a signal expression describing the set of events that will be filtered for the result. /// A strict Seq filter expression to match (text expressions must be in double quotes). To - /// convert a "fuzzy" filter into a strict one the way the Seq UI does, use connection.Expressions.ToStrictAsync(). + /// convert a "fuzzy" filter into a strict one the way the Seq UI does, use . /// If specified, the event's message template and properties will be rendered into its property. /// Values for any free variables that appear in . /// Token through which the operation can be cancelled. @@ -405,7 +405,7 @@ public async IAsyncEnumerable StreamAsync( /// created but not saved, a signal from another server, or the modified representation of an entity already persisted. /// If provided, a signal expression describing the set of events that will be filtered for the result. /// A strict Seq filter expression to match (text expressions must be in double quotes). To - /// convert a "fuzzy" filter into a strict one the way the Seq UI does, use connection.Expressions.ToStrictAsync(). + /// convert a "fuzzy" filter into a strict one the way the Seq UI does, use . /// If specified, the event's message template and properties will be rendered into its property. /// If specified, compact JSON format will be requested instead of the default format. /// Values for any free variables that appear in . diff --git a/src/Seq.Api/ResourceGroups/ExpressionsResourceGroup.cs b/src/Seq.Api/ResourceGroups/ExpressionsResourceGroup.cs index 7474a74..16ad9f2 100644 --- a/src/Seq.Api/ResourceGroups/ExpressionsResourceGroup.cs +++ b/src/Seq.Api/ResourceGroups/ExpressionsResourceGroup.cs @@ -17,46 +17,50 @@ using System.Threading.Tasks; using Seq.Api.Model.Expressions; -namespace Seq.Api.ResourceGroups +namespace Seq.Api.ResourceGroups; + +/// +/// Perform operations on queries and filter expressions. +/// +public class ExpressionsResourceGroup : ApiResourceGroup { + internal ExpressionsResourceGroup(ILoadResourceGroup connection) + : base("Expressions", connection) + { + } + /// - /// Perform operations on queries and filter expressions. + /// Convert an expression in the relaxed syntax supported by the filter bar, to the strictly-valid + /// syntax required by API interactions. /// - public class ExpressionsResourceGroup : ApiResourceGroup + /// The (potentially) relaxed-syntax expression. + /// A allowing the operation to be canceled. + /// The expression in a strictly-valid form. + public Task ToStrictAsync(string fuzzy, CancellationToken cancellationToken = default) { - internal ExpressionsResourceGroup(ILoadResourceGroup connection) - : base("Expressions", connection) - { - } - - /// - /// Convert an expression in the relaxed syntax supported by the filter bar, to the strictly-valid - /// syntax required by API interactions. - /// - /// The (potentially) relaxed-syntax expression. - /// A allowing the operation to be canceled. - /// The expression in a strictly-valid form. - public Task ToStrictAsync(string fuzzy, CancellationToken cancellationToken = default) + var parameters = new Dictionary { - return GroupGetAsync("ToStrict", new Dictionary - { - {"fuzzy", fuzzy} - }, cancellationToken); - } + [nameof(fuzzy)] = fuzzy + }; + return GroupGetAsync("ToStrict", parameters, cancellationToken); + } - /// - /// Convert an expression in the relaxed syntax supported by the filter bar, to the strict and limited - /// syntax required within SQL queries. - /// - /// The (potentially) relaxed-syntax expression. - /// A allowing the operation to be canceled. - /// The expression in a form that can be used within SQL queries. - public Task ToSqlAsync(string fuzzy, CancellationToken cancellationToken = default) + /// + /// Convert an expression in the relaxed syntax supported by the filter bar, to the strict and limited + /// syntax required within SQL queries. + /// + /// The (potentially) relaxed-syntax expression. + /// The name of the storage object that the expression will be evaluated against; accepted + /// values are stream and series. This influences the processing of "free text" expressions. + /// A allowing the operation to be canceled. + /// The expression in a form that can be used within SQL queries. + public Task ToSqlAsync(string fuzzy, string schema = "stream", CancellationToken cancellationToken = default) + { + var parameters = new Dictionary { - return GroupGetAsync("ToSql", new Dictionary - { - {"fuzzy", fuzzy} - }, cancellationToken); - } + [nameof(fuzzy)] = fuzzy, + [nameof(schema)] = schema + }; + return GroupGetAsync("ToSql", parameters, cancellationToken); } -} \ No newline at end of file +} diff --git a/src/Seq.Api/ResourceGroups/MetricsResourceGroup.cs b/src/Seq.Api/ResourceGroups/MetricsResourceGroup.cs new file mode 100644 index 0000000..182c7c0 --- /dev/null +++ b/src/Seq.Api/ResourceGroups/MetricsResourceGroup.cs @@ -0,0 +1,117 @@ +// Copyright © Datalust and contributors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Seq.Api.Model.Metrics; +using Seq.Api.Model.Shared; +namespace Seq.Api.ResourceGroups; + +/// +/// Retrieve information about the metrics stored in this Seq instance. +/// +public class MetricsResourceGroup : ApiResourceGroup +{ + internal MetricsResourceGroup(ILoadResourceGroup connection) + : base("Metrics", connection) + { + } + + /// + /// Retrieve metric definitions for samples matching a set of search criteria. + /// + /// Expressions naming any properties that determine the uniqueness/identity of metric definitions. + /// A strict Seq filter expression to match (text expressions must be in double quotes). To + /// convert a "fuzzy" filter into a strict one the way the Seq UI does, use . + /// The number of definitions to retrieve. If not specified will default to 30. + /// The earliest timestamp from which to include events in the query result. + /// The exclusive latest timestamp to which events are included in the query result. The default is the current time. + /// The query timeout; if not specified, the query will run until completion. + /// Values for any free variables that appear in . + /// Enable detailed (server-side) query tracing. + /// Token through which the operation can be cancelled. + /// A structured result set. + public async Task SearchAsync( + List groups = null, + string filter = null, + int count = 30, + DateTime? rangeStartUtc = null, + DateTime? rangeEndUtc = null, + TimeSpan? timeout = null, + Dictionary variables = null, + bool trace = false, + CancellationToken cancellationToken = default) + { + var parameters = MakeParameters(groups, filter, count, rangeStartUtc, rangeEndUtc, timeout, trace); + var body = new EvaluationContextPart { Variables = variables }; + return await GroupPostAsync("Search", body, parameters, cancellationToken).ConfigureAwait(false); + } + + /// + /// Retrieve information about the labels available for filtering samples matching a set of search criteria. + /// + /// The number of definitions to retrieve. If not specified will default to 30. + /// Optionally, the name of a metric to limit dimension search to. By default, dimensions + /// for all metrics are returned. + /// The earliest timestamp from which to include events in the query result. + /// The exclusive latest timestamp to which events are included in the query result. The default is the current time. + /// The query timeout; if not specified, the query will run until completion. + /// Enable detailed (server-side) query tracing. + /// Token through which the operation can be cancelled. + /// A structured result set. + public async Task> ListDimensionsAsync( + int count = 30, + string metric = null, + DateTime? rangeStartUtc = null, + DateTime? rangeEndUtc = null, + TimeSpan? timeout = null, + bool trace = false, + CancellationToken cancellationToken = default) + { + var parameters = MakeParameters(null, null, count, rangeStartUtc, rangeEndUtc, timeout, trace); + if (metric != null) + parameters.Add(nameof(metric), metric); + var body = new EvaluationContextPart(); + return await GroupPostAsync>("Dimensions", body, parameters, cancellationToken).ConfigureAwait(false); + } + + static Dictionary MakeParameters(List groups, string filter, int count, DateTime? rangeStartUtc, DateTime? rangeEndUtc, TimeSpan? timeout, bool trace) + { + var parameters = new Dictionary + { + [nameof(count)] = count + }; + + if (groups?.Count > 0) + parameters.Add(nameof(groups), string.Join(",", groups)); + + if (!string.IsNullOrWhiteSpace(filter)) + parameters.Add(nameof(filter), filter); + + if (rangeStartUtc != null) + parameters.Add(nameof(rangeStartUtc), rangeStartUtc); + + if (rangeEndUtc != null) + parameters.Add(nameof(rangeEndUtc), rangeEndUtc.Value); + + if (timeout != null) + parameters.Add("timeoutMS", timeout.Value.TotalMilliseconds.ToString("0")); + + if (trace) + parameters.Add(nameof(trace), true); + return parameters; + } +} diff --git a/src/Seq.Api/ResourceGroups/SignalsResourceGroup.cs b/src/Seq.Api/ResourceGroups/SignalsResourceGroup.cs index 7249714..2762668 100644 --- a/src/Seq.Api/ResourceGroups/SignalsResourceGroup.cs +++ b/src/Seq.Api/ResourceGroups/SignalsResourceGroup.cs @@ -36,12 +36,13 @@ internal SignalsResourceGroup(ILoadResourceGroup connection) /// Retrieve the signal with the given id; throws if the entity does not exist. /// /// The id of the signal. + /// If true, include only partial details in the result. /// A allowing the operation to be canceled. /// The signal. - public async Task FindAsync(string id, CancellationToken cancellationToken = default) + public async Task FindAsync(string id, bool partial = false, CancellationToken cancellationToken = default) { if (id == null) throw new ArgumentNullException(nameof(id)); - return await GroupGetAsync("Item", new Dictionary { { "id", id } }, cancellationToken).ConfigureAwait(false); + return await GroupGetAsync("Item", new Dictionary { { "id", id }, { "partial", partial } }, cancellationToken).ConfigureAwait(false); } /// @@ -50,11 +51,12 @@ public async Task FindAsync(string id, CancellationToken cancellat /// If the id of a is provided, only signals owned by them will be included in the result; if /// not specified, personal signals for all owners will be listed. /// If true, shared signals will be included in the result. + /// If true, include only partial details in the result. /// allowing the operation to be canceled. /// A list containing matching signals. - public async Task> ListAsync(string ownerId = null, bool shared = false, CancellationToken cancellationToken = default) + public async Task> ListAsync(string ownerId = null, bool shared = false, bool partial = false, CancellationToken cancellationToken = default) { - var parameters = new Dictionary { { "ownerId", ownerId }, { "shared", shared } }; + var parameters = new Dictionary { { "ownerId", ownerId }, { "shared", shared }, { "partial", partial } }; return await GroupListAsync("Items", parameters, cancellationToken: cancellationToken).ConfigureAwait(false); } diff --git a/src/Seq.Api/ResourceGroups/ViewsResourceGroup.cs b/src/Seq.Api/ResourceGroups/ViewsResourceGroup.cs new file mode 100644 index 0000000..b6e0e98 --- /dev/null +++ b/src/Seq.Api/ResourceGroups/ViewsResourceGroup.cs @@ -0,0 +1,106 @@ +// Copyright © Datalust and contributors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Seq.Api.Model; +using Seq.Api.Model.Metrics; +using Seq.Api.Model.Users; + +namespace Seq.Api.ResourceGroups; + +/// +/// Perform operations on metrics views. A view is a collection of filters, groupings, and pinned charts used to +/// populate the Seq Metrics screen. +/// +public class ViewsResourceGroup : ApiResourceGroup +{ + internal ViewsResourceGroup(ILoadResourceGroup connection) + : base("Views", connection) + { + } + + /// + /// Retrieve the view with the given id; throws if the entity does not exist. + /// + /// The id of the view. + /// If true, include only partial details in the result. + /// A allowing the operation to be canceled. + /// The view. + public async Task FindAsync(string id, bool partial = false, CancellationToken cancellationToken = default) + { + if (id == null) throw new ArgumentNullException(nameof(id)); + return await GroupGetAsync("Item", new Dictionary { { "id", id }, { "partial", partial } }, cancellationToken).ConfigureAwait(false); + } + + /// + /// Retrieve views. + /// + /// If the id of a is provided, only views owned by them will be included in the result; if + /// not specified, personal views for all owners will be listed. + /// If true, shared views will be included in the result. + /// If true, include only partial details in the result. + /// allowing the operation to be canceled. + /// A list containing matching views. + public async Task> ListAsync(string ownerId = null, bool shared = false, bool partial = false, CancellationToken cancellationToken = default) + { + var parameters = new Dictionary { { "ownerId", ownerId }, { "shared", shared }, { "partial", partial } }; + return await GroupListAsync("Items", parameters, cancellationToken: cancellationToken).ConfigureAwait(false); + } + + /// + /// Construct a view with server defaults pre-initialized. + /// + /// allowing the operation to be canceled. + /// The unsaved view. + public async Task TemplateAsync(CancellationToken cancellationToken = default) + { + return await GroupGetAsync("Template", cancellationToken: cancellationToken).ConfigureAwait(false); + } + + /// + /// Add a new view. + /// + /// The view to add. + /// A allowing the operation to be canceled. + /// The view, with server-allocated properties such as initialized. + public async Task AddAsync(ViewEntity entity, CancellationToken cancellationToken = default) + { + return await GroupCreateAsync(entity, cancellationToken: cancellationToken).ConfigureAwait(false); + } + + /// + /// Remove an existing view. + /// + /// The view to remove. + /// A allowing the operation to be canceled. + /// A task indicating completion. + public async Task RemoveAsync(ViewEntity entity, CancellationToken cancellationToken = default) + { + await Client.DeleteAsync(entity, "Self", entity, cancellationToken: cancellationToken).ConfigureAwait(false); + } + + /// + /// Update an existing view. + /// + /// The view to update. + /// A allowing the operation to be canceled. + /// A task indicating completion. + public async Task UpdateAsync(ViewEntity entity, CancellationToken cancellationToken = default) + { + await Client.PutAsync(entity, "Self", entity, cancellationToken: cancellationToken).ConfigureAwait(false); + } +} \ No newline at end of file diff --git a/src/Seq.Api/Seq.Api.csproj b/src/Seq.Api/Seq.Api.csproj index 19e11c8..8672c2c 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. - 2025.2.2 + 2026.1.0 Datalust;Contributors netstandard2.0;net6.0;net8.0 true @@ -23,13 +23,21 @@ - + - + - - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Seq.Api/SeqConnection.cs b/src/Seq.Api/SeqConnection.cs index 9fc90f7..29f90e2 100644 --- a/src/Seq.Api/SeqConnection.cs +++ b/src/Seq.Api/SeqConnection.cs @@ -143,6 +143,11 @@ public void Dispose() /// Perform operations on the Seq license certificate. /// public LicensesResourceGroup Licenses => new(this); + + /// + /// Perform operations on metrics definitions. + /// + public MetricsResourceGroup Metrics => new(this); /// /// Perform operations on permalinked events. @@ -189,6 +194,11 @@ public void Dispose() /// public UsersResourceGroup Users => new(this); + /// + /// Perform operations on metrics views. + /// + public ViewsResourceGroup Views => new(this); + /// /// Perform operations on workspaces. ///