Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Industrial log analytics #400

Merged
merged 9 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
26 changes: 26 additions & 0 deletions CogniteSdk.Types/Alpha/LogAnalytics/Log.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using CogniteSdk.Beta.DataModels;

namespace CogniteSdk.Alpha
{
/// <summary>
/// A retrieved log from ILA.
/// </summary>
/// <typeparam name="T">Type of the properties bag.</typeparam>
public class Log<T>
{
/// <summary>
/// Id of the space the log belongs to.
/// </summary>
public string Space { get; set; }
/// <summary>
/// The number of milliseconds since 00:00:00 Thursday 1 January 1970, Coordinated
/// Unversal Time (UTC) minus leap seconds.
/// </summary>
public long CreatedTime { get; set; }
/// <summary>
/// Spaces to containers to properties and their values for the requested containers.
/// You can use <see cref="StandardInstanceData"/> as a fallback for generic results here.
/// </summary>
public T Properties { get; set; }
}
}
36 changes: 36 additions & 0 deletions CogniteSdk.Types/Alpha/LogAnalytics/LogIngest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Collections.Generic;
using CogniteSdk.Beta.DataModels;

namespace CogniteSdk.Alpha
{
/// <summary>
/// ILA Log item to ingest.
/// </summary>
public class LogItem
{
/// <summary>
/// Id of the space the log belongs to.
/// </summary>
public string Space { get; set; }
/// <summary>
/// List of source properties to write. The properties are from the container(s) making up this log.
/// Note that `InstanceData` is abstract, you should generally use `InstanceData[T]`
/// to assign types to the log item, but since log sources currently only write to
/// containers, it is usually impossible to assign only a single type to the logs.
///
/// As a fallback, you can use <see cref="StandardInstanceWriteData"/>.
/// </summary>
public IEnumerable<InstanceData> Sources { get; set; }
}

/// <summary>
/// Insertion request for ILA logs.
/// </summary>
public class LogIngest : ItemsWithoutCursor<LogItem>
{
/// <summary>
/// Name of the stream where the logs are located.
/// </summary>
public string Stream { get; set; }
}
}
167 changes: 167 additions & 0 deletions CogniteSdk.Types/Alpha/LogAnalytics/LogRetrieve.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
using CogniteSdk.Beta.DataModels;

namespace CogniteSdk.Alpha
{
/// <summary>
/// Sources to retrieve log data from.
/// </summary>
public class LogSource
{
/// <summary>
/// Container reference.
/// </summary>
public ContainerIdentifier Source { get; set; }
/// <summary>
/// List of properties to retrieve.
/// </summary>
public IEnumerable<string> Properties { get; set; }
}

/// <summary>
/// Optional attribute to extend the filter with full text search capabilities for
/// a single query in the list of log properties with OR logic.
/// </summary>
public class LogSearch
{
/// <summary>
/// Query string that will be parsed and used for search.
/// </summary>
public string Query { get; set; }
/// <summary>
/// Array of property identifiers to search through.
/// </summary>
public IEnumerable<IEnumerable<string>> Properties { get; set; }
}

/// <summary>
/// Filter on logs created within the provided range.
/// </summary>
public class CreatedTimeFilter
{
/// <summary>
/// Value must be greater than this
/// </summary>
[JsonPropertyName("gt")]
public IDMSValue GreaterThan { get; set; }

/// <summary>
/// Value must be greater than or equal to this
/// </summary>
[JsonPropertyName("gte")]
public IDMSValue GreaterThanEqual { get; set; }

/// <summary>
/// Value must be less than this
/// </summary>
[JsonPropertyName("lt")]
public IDMSValue LessThan { get; set; }

/// <summary>
/// Value must be less than or equal to this
/// </summary>
[JsonPropertyName("lte")]
public IDMSValue LessThanEqual { get; set; }
}

/// <summary>
/// Specification for sorting retrieved ILA logs.
/// </summary>
public class LogSort
{
/// <summary>
/// Property you want to sort on.
/// </summary>
public IEnumerable<string> Property { get; set; }
/// <summary>
/// Sort direction.
/// </summary>
public SortDirection Direction { get; set; }
}

/// <summary>
/// Retrieve logs from ILA.
/// </summary>
public class LogRetrieve
{
/// <summary>
/// Name of the stream where logs are located, required.
/// </summary>
public string Stream { get; set; }
/// <summary>
/// List of containers and the properties that should be selected.
///
/// Optional, if this is left out all properties are returned.
/// </summary>
public IEnumerable<LogSource> Sources { get; set; }
/// <summary>
/// Optional attribute to extend the filter with full text search capabilities
/// for a single field in the list of log properties with OR logic.
/// </summary>
public LogSearch Search { get; set; }
/// <summary>
/// A filter Domain Specific Language (DSL) used to create advanced filter queries.
///
/// Note that some filter types are not supported with ILA, see API docs.
/// </summary>
public IDMSFilter Filter { get; set; }
/// <summary>
/// Matches logs with created time within the provided range.
/// </summary>
public CreatedTimeFilter CreatedTime { get; set; }
/// <summary>
/// Maximum number of results to return. Default 10, max 10000.
/// </summary>
public int Limit { get; set; }
/// <summary>
/// Ordered list of sorting specifications.
/// </summary>
public IEnumerable<LogSort> Sort { get; set; }
}


/// <summary>
/// Request for syncing logs.
/// </summary>
public class LogSync
{
/// <summary>
/// Name of the stream where logs are located, required.
/// </summary>
public string Stream { get; set; }
/// <summary>
/// List of containers and the properties that should be selected.
///
/// Optional, if this is left out all properties are returned.
/// </summary>
public IEnumerable<LogSource> Sources { get; set; }
/// <summary>
/// A filter Domain Specific Language (DSL) used to create advanced filter queries.
///
/// Note that some filter types are not supported with ILA, see API docs.
/// </summary>
public IDMSFilter Filter { get; set; }
/// <summary>
/// A cursor returned from the previous sync request.
/// </summary>
public string Cursors { get; set; }
/// <summary>
/// Maximum number of results to return.
/// </summary>
public int Limit { get; set; }
}

/// <summary>
/// Response from an ILA sync request.
/// </summary>
/// <typeparam name="T">Type of properties in returned logs.</typeparam>
public class LogSyncResponse<T> : ItemsWithCursor<Log<T>>
{
/// <summary>
/// The attribute indiciates if there are more logs to read in storage,
/// or if the cursor points to the last item.
/// </summary>
public bool HasNext { get; set; }
}
}
3 changes: 2 additions & 1 deletion CogniteSdk.Types/Alpha/Simulators/SimulatorConverters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ public override SimulatorValue Read(ref Utf8JsonReader reader, Type typeToConver
if (listStr.Count > 0 && listDbl.Count > 0)
{
throw new JsonException("Unable to parse value of type: mixed array");
} else if (listStr.Count > 0)
}
else if (listStr.Count > 0)
{
return SimulatorValue.Create(listStr);
}
Expand Down
2 changes: 1 addition & 1 deletion CogniteSdk.Types/Common/Converters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ private string ReadValue(ref Utf8JsonReader reader, JsonSerializerOptions option
return number.ToString();
}
return reader.GetDouble().ToString();
default:
default:
throw new JsonException($"'{reader.TokenType}' is not supported");
}
}
Expand Down
80 changes: 80 additions & 0 deletions CogniteSdk/src/Resources/Alpha/LogAnalytics.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright 2024 Cognite AS
// SPDX-License-Identifier: Apache-2.0

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using CogniteSdk.Alpha;
using Microsoft.FSharp.Core;
using Oryx;

namespace CogniteSdk.Resources.Alpha
{
/// <summary>
/// Contains methods for industrial log analytics.
/// </summary>
public class LogAnalyticsResource : Resource
{
internal LogAnalyticsResource(Func<CancellationToken, Task<string>> authHandler, FSharpFunc<IHttpNext<Unit>, Task<Unit>> ctx) : base(authHandler, ctx)
{
}

/// <summary>
/// Creates a list of logs in the provided stream.
/// </summary>
/// <param name="stream">Stream to ingest logs into.</param>
/// <param name="logs">Logs to ingest.</param>
/// <param name="token">Optional cancellation token</param>
public async Task IngestAsync(string stream, IEnumerable<LogItem> logs, CancellationToken token = default)
{
if (stream is null)
{
throw new ArgumentNullException(nameof(stream));
}

var req = Oryx.Cognite.Alpha.LogAnalytics.ingest(new LogIngest
{
Stream = stream,
Items = logs,
}, GetContext(token));
await RunAsync(req).ConfigureAwait(false);
}

/// <summary>
/// Retrieve a list of logs.
/// </summary>
/// <typeparam name="T">Type of properties in the retrieved logs.</typeparam>
/// <param name="request">Log retrieval request.</param>
/// <param name="token">Optional cancellation token.</param>
/// <returns>Retrieved logs.</returns>
public async Task<IEnumerable<Log<T>>> RetrieveAsync<T>(LogRetrieve request, CancellationToken token = default)
{
if (request is null)
{
throw new ArgumentNullException(nameof(request));
}

var req = Oryx.Cognite.Alpha.LogAnalytics.retrieve<T>(request, GetContext(token));
return await RunAsync(req).ConfigureAwait(false);
}

/// <summary>
/// Synchronizes updates to logs. This endpoint will always return a cursor.
/// </summary>
/// <typeparam name="T">Type of properties in the retrieved logs.</typeparam>
/// <param name="request">Log retreival request.</param>
/// <param name="token">Optional cancellation token.</param>
/// <returns>Sync response.</returns>
public async Task<LogSyncResponse<T>> SyncAsync<T>(LogSync request, CancellationToken token = default)
{
if (request is null)
{
throw new ArgumentNullException(nameof(request));
}

var req = Oryx.Cognite.Alpha.LogAnalytics.sync<T>(request, GetContext(token));
return await RunAsync(req).ConfigureAwait(false);
}
}
}
40 changes: 40 additions & 0 deletions Oryx.Cognite/src/Alpha/LogAnalytics.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright 2024 Cognite AS
// SPDX-License-Identifier: Apache-2.0

namespace Oryx.Cognite.Alpha

open System.Collections.Generic

open Oryx
open Oryx.Cognite
open Oryx.Cognite.Alpha

open CogniteSdk.Alpha

[<RequireQualifiedAccess>]
module LogAnalytics =
[<Literal>]
let Url = "/logs"

let ingest (items: LogIngest) (source: HttpHandler<unit>) : HttpHandler<CogniteSdk.EmptyResponse> =
source
|> withLogMessage "loganalytics:ingest"
|> withAlphaHeader
|> postV10<LogIngest, CogniteSdk.EmptyResponse> items Url

let retrieve<'T> (request: LogRetrieve) (source: HttpHandler<unit>) : HttpHandler<Log<'T> seq> =
http {
let! ret =
source
|> withLogMessage "loganalytics:retrieve"
|> withCompletion System.Net.Http.HttpCompletionOption.ResponseHeadersRead
|> postV10<_, CogniteSdk.ItemsWithoutCursor<_>> request (Url +/ "list")

return ret.Items
}

let sync<'T> (request: LogSync) (source: HttpHandler<unit>) : HttpHandler<LogSyncResponse<'T>> =
source
|> withLogMessage "loganalytics:sync"
|> withCompletion System.Net.Http.HttpCompletionOption.ResponseHeadersRead
|> postV10 request (Url +/ "sync")
1 change: 1 addition & 0 deletions Oryx.Cognite/src/Oryx.Cognite.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
<Compile Include="Alpha/Handler.fs" />
<Compile Include="Alpha/DataPoints.fs" />
<Compile Include="Alpha/Simulators.fs" />
<Compile Include="Alpha/LogAnalytics.fs" />
<None Include="..\..\LICENSE" Pack="true" Visible="false" PackagePath="" />
</ItemGroup>
<ItemGroup>
Expand Down
Loading