-
Notifications
You must be signed in to change notification settings - Fork 5.1k
[LiveMetrics] add support for Logs #42889
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| namespace Azure.Monitor.OpenTelemetry.LiveMetrics | ||
| { | ||
| public partial class LiveMetricsExporterOptions : Azure.Core.ClientOptions | ||
| { | ||
| public LiveMetricsExporterOptions() { } | ||
| public string ConnectionString { get { throw null; } set { } } | ||
| public Azure.Core.TokenCredential Credential { get { throw null; } set { } } | ||
| public bool EnableLiveMetrics { get { throw null; } set { } } | ||
| } | ||
| public static partial class LiveMetricsExtensions | ||
| { | ||
| public static OpenTelemetry.Logs.OpenTelemetryLoggerOptions AddLiveMetrics(this OpenTelemetry.Logs.OpenTelemetryLoggerOptions loggerOptions, System.Action<Azure.Monitor.OpenTelemetry.LiveMetrics.LiveMetricsExporterOptions> configure = null) { throw null; } | ||
| public static OpenTelemetry.Trace.TracerProviderBuilder AddLiveMetrics(this OpenTelemetry.Trace.TracerProviderBuilder builder, System.Action<Azure.Monitor.OpenTelemetry.LiveMetrics.LiveMetricsExporterOptions> configure = null, string name = null) { throw null; } | ||
| } | ||
| } | ||
| namespace Azure.Monitor.OpenTelemetry.LiveMetrics.Models | ||
| { | ||
| [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] | ||
| public readonly partial struct DerivedMetricInfoAggregation : System.IEquatable<Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DerivedMetricInfoAggregation> | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this a public API?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will go away. Builds are currently failing because our api files are out of sync. |
||
| { | ||
| private readonly object _dummy; | ||
| private readonly int _dummyPrimitive; | ||
| public DerivedMetricInfoAggregation(string value) { throw null; } | ||
| public static Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DerivedMetricInfoAggregation Avg { get { throw null; } } | ||
| public static Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DerivedMetricInfoAggregation Max { get { throw null; } } | ||
| public static Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DerivedMetricInfoAggregation Min { get { throw null; } } | ||
| public static Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DerivedMetricInfoAggregation Sum { get { throw null; } } | ||
| public bool Equals(Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DerivedMetricInfoAggregation other) { throw null; } | ||
| [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] | ||
| public override bool Equals(object obj) { throw null; } | ||
| [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] | ||
| public override int GetHashCode() { throw null; } | ||
| public static bool operator ==(Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DerivedMetricInfoAggregation left, Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DerivedMetricInfoAggregation right) { throw null; } | ||
| public static implicit operator Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DerivedMetricInfoAggregation (string value) { throw null; } | ||
| public static bool operator !=(Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DerivedMetricInfoAggregation left, Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DerivedMetricInfoAggregation right) { throw null; } | ||
| public override string ToString() { throw null; } | ||
| } | ||
| [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] | ||
| public readonly partial struct DocumentFilterConjunctionGroupInfoTelemetryType : System.IEquatable<Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentFilterConjunctionGroupInfoTelemetryType> | ||
| { | ||
| private readonly object _dummy; | ||
| private readonly int _dummyPrimitive; | ||
| public DocumentFilterConjunctionGroupInfoTelemetryType(string value) { throw null; } | ||
| public static Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentFilterConjunctionGroupInfoTelemetryType Dependency { get { throw null; } } | ||
| public static Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentFilterConjunctionGroupInfoTelemetryType Event { get { throw null; } } | ||
| public static Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentFilterConjunctionGroupInfoTelemetryType Exception { get { throw null; } } | ||
| public static Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentFilterConjunctionGroupInfoTelemetryType Metric { get { throw null; } } | ||
| public static Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentFilterConjunctionGroupInfoTelemetryType PerformanceCounter { get { throw null; } } | ||
| public static Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentFilterConjunctionGroupInfoTelemetryType Request { get { throw null; } } | ||
| public static Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentFilterConjunctionGroupInfoTelemetryType Trace { get { throw null; } } | ||
| public bool Equals(Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentFilterConjunctionGroupInfoTelemetryType other) { throw null; } | ||
| [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] | ||
| public override bool Equals(object obj) { throw null; } | ||
| [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] | ||
| public override int GetHashCode() { throw null; } | ||
| public static bool operator ==(Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentFilterConjunctionGroupInfoTelemetryType left, Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentFilterConjunctionGroupInfoTelemetryType right) { throw null; } | ||
| public static implicit operator Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentFilterConjunctionGroupInfoTelemetryType (string value) { throw null; } | ||
| public static bool operator !=(Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentFilterConjunctionGroupInfoTelemetryType left, Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentFilterConjunctionGroupInfoTelemetryType right) { throw null; } | ||
| public override string ToString() { throw null; } | ||
| } | ||
| [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] | ||
| public readonly partial struct DocumentIngressDocumentType : System.IEquatable<Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentIngressDocumentType> | ||
| { | ||
| private readonly object _dummy; | ||
| private readonly int _dummyPrimitive; | ||
| public DocumentIngressDocumentType(string value) { throw null; } | ||
| public static Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentIngressDocumentType Event { get { throw null; } } | ||
| public static Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentIngressDocumentType Exception { get { throw null; } } | ||
| public static Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentIngressDocumentType RemoteDependency { get { throw null; } } | ||
| public static Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentIngressDocumentType Request { get { throw null; } } | ||
| public static Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentIngressDocumentType Trace { get { throw null; } } | ||
| public bool Equals(Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentIngressDocumentType other) { throw null; } | ||
| [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] | ||
| public override bool Equals(object obj) { throw null; } | ||
| [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] | ||
| public override int GetHashCode() { throw null; } | ||
| public static bool operator ==(Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentIngressDocumentType left, Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentIngressDocumentType right) { throw null; } | ||
| public static implicit operator Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentIngressDocumentType (string value) { throw null; } | ||
| public static bool operator !=(Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentIngressDocumentType left, Azure.Monitor.OpenTelemetry.LiveMetrics.Models.DocumentIngressDocumentType right) { throw null; } | ||
| public override string ToString() { throw null; } | ||
| } | ||
| [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] | ||
| public readonly partial struct FilterInfoPredicate : System.IEquatable<Azure.Monitor.OpenTelemetry.LiveMetrics.Models.FilterInfoPredicate> | ||
| { | ||
| private readonly object _dummy; | ||
| private readonly int _dummyPrimitive; | ||
| public FilterInfoPredicate(string value) { throw null; } | ||
| public static Azure.Monitor.OpenTelemetry.LiveMetrics.Models.FilterInfoPredicate Contains { get { throw null; } } | ||
| public static Azure.Monitor.OpenTelemetry.LiveMetrics.Models.FilterInfoPredicate DoesNotContain { get { throw null; } } | ||
| public static Azure.Monitor.OpenTelemetry.LiveMetrics.Models.FilterInfoPredicate Equal { get { throw null; } } | ||
| public static Azure.Monitor.OpenTelemetry.LiveMetrics.Models.FilterInfoPredicate GreaterThan { get { throw null; } } | ||
| public static Azure.Monitor.OpenTelemetry.LiveMetrics.Models.FilterInfoPredicate GreaterThanOrEqual { get { throw null; } } | ||
| public static Azure.Monitor.OpenTelemetry.LiveMetrics.Models.FilterInfoPredicate LessThan { get { throw null; } } | ||
| public static Azure.Monitor.OpenTelemetry.LiveMetrics.Models.FilterInfoPredicate LessThanOrEqual { get { throw null; } } | ||
| public static Azure.Monitor.OpenTelemetry.LiveMetrics.Models.FilterInfoPredicate NotEqual { get { throw null; } } | ||
| public bool Equals(Azure.Monitor.OpenTelemetry.LiveMetrics.Models.FilterInfoPredicate other) { throw null; } | ||
| [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] | ||
| public override bool Equals(object obj) { throw null; } | ||
| [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] | ||
| public override int GetHashCode() { throw null; } | ||
| public static bool operator ==(Azure.Monitor.OpenTelemetry.LiveMetrics.Models.FilterInfoPredicate left, Azure.Monitor.OpenTelemetry.LiveMetrics.Models.FilterInfoPredicate right) { throw null; } | ||
| public static implicit operator Azure.Monitor.OpenTelemetry.LiveMetrics.Models.FilterInfoPredicate (string value) { throw null; } | ||
| public static bool operator !=(Azure.Monitor.OpenTelemetry.LiveMetrics.Models.FilterInfoPredicate left, Azure.Monitor.OpenTelemetry.LiveMetrics.Models.FilterInfoPredicate right) { throw null; } | ||
| public override string ToString() { throw null; } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ | |
| using System.Text; | ||
| using Azure.Monitor.OpenTelemetry.Exporter.Internals; | ||
| using Azure.Monitor.OpenTelemetry.LiveMetrics.Models; | ||
| using OpenTelemetry.Logs; | ||
| using ExceptionDocument = Azure.Monitor.OpenTelemetry.LiveMetrics.Models.Exception; | ||
|
|
||
| namespace Azure.Monitor.OpenTelemetry.LiveMetrics.Internals.DataCollection | ||
|
|
@@ -170,6 +171,16 @@ internal static ExceptionDocument CreateException(string exceptionType, string e | |
| return exceptionDocumentIngress; | ||
| } | ||
|
|
||
| internal static Models.Trace ConvertToTrace(LogRecord logRecord) | ||
| { | ||
| return new Models.Trace() | ||
| { | ||
| DocumentType = DocumentIngressDocumentType.Trace, | ||
| Message = logRecord.FormattedMessage ?? logRecord.Body, // TODO: MAY NEED TO BUILD THE FORMATTED MESSAGE IF NOT AVAILABLE | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It seems that Application Insights would always build the fully formatted string. I don't think we should do that here. In a future PR, I think we could explore building a string that contains the template and the key-value-pairs. (ex: "Hello {name}. name: World"). I don't want to do this extra work until I have the unit test project up and working for this project. I propose leaving this as a TODO for now. |
||
| // TODO: Properties = new Dictionary<string, string>(), - UX supports up to 10 custom properties | ||
| }; | ||
| } | ||
|
|
||
| [MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
| internal static bool IsHttpSuccess(Activity activity, string? responseCode) | ||
| { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using System.Collections.Generic; | ||
| using Azure.Monitor.OpenTelemetry.Exporter.Internals.Platform; | ||
|
|
||
| namespace Azure.Monitor.OpenTelemetry.LiveMetrics.Internals | ||
| { | ||
| internal sealed class ManagerFactory | ||
| { | ||
| public static readonly ManagerFactory Instance = new(); | ||
|
|
||
| internal readonly Dictionary<string, Manager> _runners = new(); | ||
| private readonly object _lockObj = new(); | ||
|
|
||
| public Manager Get(LiveMetricsExporterOptions options) | ||
| { | ||
| var key = options.ConnectionString ?? string.Empty; | ||
|
|
||
| if (!_runners.TryGetValue(key, out Manager? runner)) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does it mean if a customer provides an empty connection string? Do we still continue in this case? |
||
| { | ||
| lock (_lockObj) | ||
| { | ||
| if (!_runners.TryGetValue(key, out runner)) | ||
| { | ||
| runner = new Manager(options, new DefaultPlatform()); | ||
|
|
||
| _runners.Add(key, runner); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return runner; | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,10 +4,10 @@ | |
| #nullable disable | ||
|
|
||
| using System; | ||
| using Azure.Monitor.OpenTelemetry.Exporter.Internals.Platform; | ||
| using Azure.Monitor.OpenTelemetry.LiveMetrics.Internals; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
| using Microsoft.Extensions.Options; | ||
| using OpenTelemetry.Logs; | ||
| using OpenTelemetry.Metrics; | ||
| using OpenTelemetry.Trace; | ||
|
|
||
|
|
@@ -67,9 +67,36 @@ public static TracerProviderBuilder AddLiveMetrics( | |
| } | ||
|
|
||
| // INITIALIZE INTERNALS | ||
| var manager = new Manager(exporterOptions, new DefaultPlatform()); | ||
| var manager = ManagerFactory.Instance.Get(exporterOptions); | ||
| return new LiveMetricsActivityProcessor(manager); | ||
| }); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// TODO: Add documentation. | ||
| /// </summary> | ||
| /// <param name="loggerOptions"></param> | ||
| /// <param name="configure"></param> | ||
| /// <returns></returns> | ||
| /// <exception cref="ArgumentNullException"></exception> | ||
| public static OpenTelemetryLoggerOptions AddLiveMetrics( | ||
| this OpenTelemetryLoggerOptions loggerOptions, | ||
| Action<LiveMetricsExporterOptions> configure = null) | ||
| { | ||
| if (loggerOptions == null) | ||
| { | ||
| throw new ArgumentNullException(nameof(loggerOptions)); | ||
| } | ||
|
|
||
| return loggerOptions.AddProcessor(sp => | ||
| { | ||
| var options = new LiveMetricsExporterOptions(); | ||
| configure?.Invoke(options); | ||
|
|
||
| // INITIALIZE INTERNALS | ||
| var manager = ManagerFactory.Instance.Get(options); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should use ServiceCollections rather than getting an instance from singleton. This way we could avoid the complete ManagerFactory. Please note live metrics support is only available through distro. |
||
| return new LiveMetricsLogProcessor(manager); | ||
| }); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using System; | ||
| using Azure.Monitor.OpenTelemetry.LiveMetrics.Internals; | ||
| using Azure.Monitor.OpenTelemetry.LiveMetrics.Internals.DataCollection; | ||
| using OpenTelemetry; | ||
| using OpenTelemetry.Logs; | ||
|
|
||
| namespace Azure.Monitor.OpenTelemetry.LiveMetrics | ||
| { | ||
| internal class LiveMetricsLogProcessor : BaseProcessor<LogRecord> | ||
| { | ||
| private bool _disposed; | ||
| private LiveMetricsResource? _resource; | ||
| private readonly Manager _manager; | ||
|
|
||
| internal LiveMetricsResource? LiveMetricsResource => _resource ??= ParentProvider?.GetResource().CreateAzureMonitorResource(); | ||
|
|
||
| public LiveMetricsLogProcessor(Manager manager) | ||
| { | ||
| _manager = manager; | ||
| } | ||
|
|
||
| public override void OnEnd(LogRecord data) | ||
| { | ||
| // Check if live metrics is enabled. | ||
| if (!_manager.ShouldCollect()) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| // Resource is not available at initialization and must be set later. | ||
| if (_manager.LiveMetricsResource == null && LiveMetricsResource != null) | ||
| { | ||
| _manager.LiveMetricsResource = LiveMetricsResource; | ||
| } | ||
|
|
||
| if (data.Exception is null) | ||
| { | ||
| AddLogDocument(data); | ||
| } | ||
| else | ||
| { | ||
| AddExceptionDocument(data.Exception); | ||
| } | ||
| } | ||
|
|
||
| protected override void Dispose(bool disposing) | ||
| { | ||
| if (!_disposed) | ||
| { | ||
| if (disposing) | ||
| { | ||
| try | ||
| { | ||
| _manager.Dispose(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If manager is shared for the same |
||
| } | ||
| catch (System.Exception) | ||
| { | ||
| } | ||
| } | ||
|
|
||
| _disposed = true; | ||
| } | ||
|
|
||
| base.Dispose(disposing); | ||
| } | ||
|
|
||
| private void AddLogDocument(LogRecord logRecord) | ||
| { | ||
| var logDocument = DocumentHelper.ConvertToTrace(logRecord); | ||
| _manager._documentBuffer.WriteDocument(logDocument); | ||
| } | ||
|
|
||
| private void AddExceptionDocument(Exception exception) | ||
| { | ||
| var exceptionDocument = DocumentHelper.CreateException(exceptionType: exception.GetType().Name, exceptionMessage: exception.Message); | ||
| _manager._documentBuffer.WriteDocument(exceptionDocument); | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be an internal implementation and shouldn't be a new API.
Please mark this class and methods as internal.