diff --git a/.vsts/linux-build.yml b/.vsts/linux-build.yml index da01572659..3df2f59681 100644 --- a/.vsts/linux-build.yml +++ b/.vsts/linux-build.yml @@ -20,7 +20,7 @@ steps: inputs: command: "test" projects: "Test/**/*netcoreapp20*.csproj" - arguments: "--configuration Release --filter TestCategory!=WindowsOnly" + arguments: "--configuration Release -l trx --filter TestCategory!=WindowsOnly" - task: DotNetCoreInstaller@0 inputs: @@ -30,9 +30,12 @@ steps: inputs: command: "test" projects: "Test/**/*netcoreapp11*.csproj" - arguments: "--configuration Release --filter TestCategory!=WindowsOnly" + arguments: "--configuration Release -l trx --filter TestCategory!=WindowsOnly" - task: PublishTestResults@2 + inputs: + testRunner: "VSTest" + testResultsFiles: "**/*.trx" - task: DotNetCoreCLI@1 inputs: diff --git a/CHANGELOG.md b/CHANGELOG.md index b52e1095d7..06bea0aa95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,20 @@ This changelog will be used to generate documentation on [release notes page](http://azure.microsoft.com/documentation/articles/app-insights-release-notes-dotnet/). +## Version 2.8.0-beta1 +- [Add a new distict properties collection, GlobalProperties, on TelemetryContext, and obsolete the Properties on TelemetryContext.](https://github.com/Microsoft/ApplicationInsights-dotnet/issues/820) +- [Added support for strongly typed extensibility for Telemetry types using IExtension.](https://github.com/Microsoft/ApplicationInsights-dotnet/issues/871) +- [New method SerializeData(ISerializationWriter writer) defined in ITelemetry. All existing types implement this method to emit information about it's fields to channels who can serialize this data] + (continuation of https://github.com/Microsoft/ApplicationInsights-dotnet/issues/871) +- [Allow to track PageViewPerformance data type](https://github.com/Microsoft/ApplicationInsights-dotnet/issues/673). +- Added method `ExceptionDetailsInfoList` on `ExceptionTelemetry` class that gives control to user to update exception +message and exception type of underlying `System.Exception` object that user wants to send to telemetry. Related discussion is [here](https://github.com/Microsoft/ApplicationInsights-dotnet/issues/498). +- Added an option of creating ExceptionTelemetry object off of custom exception information rather than a System.Exception object. +- [Add support for hex values in config](https://github.com/Microsoft/ApplicationInsights-dotnet/issues/551) + +## Version 2.7.0 +- Metrics: Renamed TryTrackValue(..) into TrackValue(..). +- Metrics: Removed some superfluous public constants. ## Version 2.7.0 - Metrics: Renamed TryTrackValue(..) into TrackValue(..). @@ -10,7 +24,7 @@ This changelog will be used to generate documentation on [release notes page](ht ## Version 2.7.0-beta3 - [Allow to set flags on event](https://github.com/Microsoft/ApplicationInsights-dotnet/issues/844). It will be used in conjunction with the feature that will allow to keep IP addresses. - [Fix: SerializationException resolving Activity in cross app-domain calls](https://github.com/Microsoft/ApplicationInsights-dotnet-server/issues/613) -- [Make HttpClient instance static to avoid re-creating with every transmission. This had caused connection/memory leaks in .net core 2.1] (https://github.com/Microsoft/ApplicationInsights-dotnet/issues/594) +- [Make HttpClient instance static to avoid re-creating with every transmission. This had caused connection/memory leaks in .net core 2.1](https://github.com/Microsoft/ApplicationInsights-dotnet/issues/594) Related: (https://github.com/Microsoft/ApplicationInsights-aspnetcore/issues/690) ## Version 2.7.0-beta2 @@ -57,7 +71,7 @@ This changelog will be used to generate documentation on [release notes page](ht - Remove calculation of sampling-score based on Context.User.Id [Issue #625](https://github.com/Microsoft/ApplicationInsights-dotnet/issues/625) - New sdk-driven "heartbeat" functionality added which sends health status at pre-configured intervals. See [extending heartbeat properties doc for more information](./docs/ExtendingHeartbeatProperties.md) - Fixes a bug in ServerTelemetryChannel which caused application to crash on non-windows platforms. - [Details on fix and workaround #654] (https://github.com/Microsoft/ApplicationInsights-dotnet/issues/654) + [Details on fix and workaround #654](https://github.com/Microsoft/ApplicationInsights-dotnet/issues/654) Original issue (https://github.com/Microsoft/ApplicationInsights-aspnetcore/issues/551) - [Fixed a bug with the `AdaptiveSamplingTelemetryProcessor` that would cause starvation over time. Issue #756 (dotnet-server)](https://github.com/Microsoft/ApplicationInsights-dotnet-server/issues/756) - Updated solution to build on Mac! @@ -101,7 +115,7 @@ This changelog will be used to generate documentation on [release notes page](ht - [Fixed a bug which caused SDK to stop sending telemetry.](https://github.com/Microsoft/ApplicationInsights-dotnet-server/issues/480) ## Version 2.3.0-beta3 -- [Added overloads of TelemetryClientExtensions.StartOperation.] (https://github.com/Microsoft/ApplicationInsights-dotnet/issues/163) +- [Added overloads of TelemetryClientExtensions.StartOperation.](https://github.com/Microsoft/ApplicationInsights-dotnet/issues/163) - Fire new ETW events for Operation Start/Stop. ## Version 2.3.0-beta2 diff --git a/GlobalStaticVersion.props b/GlobalStaticVersion.props index 29078572dd..348586b4b6 100644 --- a/GlobalStaticVersion.props +++ b/GlobalStaticVersion.props @@ -6,10 +6,10 @@ Update for every public release. --> 2 - 7 - 2 + 8 + 0 - + beta1 - 2018-05-21 + 2018-08-01 $([MSBuild]::Divide($([System.DateTime]::Now.Subtract($([System.DateTime]::Parse($(SemanticVersionDate)))).TotalMinutes), 5).ToString('F0')) diff --git a/Microsoft.ApplicationInsights.sln b/Microsoft.ApplicationInsights.sln index 7eea38ca81..80e7ce1b31 100644 --- a/Microsoft.ApplicationInsights.sln +++ b/Microsoft.ApplicationInsights.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26430.16 +VisualStudioVersion = 15.0.27130.2036 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.ApplicationInsights.Tests", "Microsoft.ApplicationInsights.Tests", "{C2FEEDE5-8CAE-41A4-8932-42D284A86EA7}" EndProject diff --git a/PublicAPI/Microsoft.ApplicationInsights.dll/net45/PublicAPI.Shipped.txt b/PublicAPI/Microsoft.ApplicationInsights.dll/net45/PublicAPI.Shipped.txt index 916d1e920e..8007a9f1fd 100644 --- a/PublicAPI/Microsoft.ApplicationInsights.dll/net45/PublicAPI.Shipped.txt +++ b/PublicAPI/Microsoft.ApplicationInsights.dll/net45/PublicAPI.Shipped.txt @@ -99,6 +99,14 @@ Microsoft.ApplicationInsights.DataContracts.ExceptionHandledAt Microsoft.ApplicationInsights.DataContracts.ExceptionHandledAt.Platform = 2 -> Microsoft.ApplicationInsights.DataContracts.ExceptionHandledAt Microsoft.ApplicationInsights.DataContracts.ExceptionHandledAt.Unhandled = 0 -> Microsoft.ApplicationInsights.DataContracts.ExceptionHandledAt Microsoft.ApplicationInsights.DataContracts.ExceptionHandledAt.UserCode = 1 -> Microsoft.ApplicationInsights.DataContracts.ExceptionHandledAt +Microsoft.ApplicationInsights.DataContracts.ExceptionDetailsInfo +Microsoft.ApplicationInsights.DataContracts.ExceptionDetailsInfo.ExceptionDetailsInfo(int id, int outerId, string typeName, string message, bool hasFullStack, string stack, System.Collections.Generic.IEnumerable parsedStack) -> void +Microsoft.ApplicationInsights.DataContracts.ExceptionDetailsInfo.TypeName.get -> string +Microsoft.ApplicationInsights.DataContracts.ExceptionDetailsInfo.TypeName.set -> void +Microsoft.ApplicationInsights.DataContracts.ExceptionDetailsInfo.Message.get -> string +Microsoft.ApplicationInsights.DataContracts.ExceptionDetailsInfo.Message.set -> void +Microsoft.ApplicationInsights.DataContracts.StackFrame +Microsoft.ApplicationInsights.DataContracts.StackFrame.StackFrame(string assembly, string fileName, int level, int line, string method) -> void Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.Context.get -> Microsoft.ApplicationInsights.DataContracts.TelemetryContext Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.DeepClone() -> Microsoft.ApplicationInsights.Channel.ITelemetry @@ -106,8 +114,10 @@ Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.Exception.get -> Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.Exception.set -> void Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.ExceptionTelemetry() -> void Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.ExceptionTelemetry(System.Exception exception) -> void +Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.ExceptionTelemetry(System.Collections.Generic.IEnumerable exceptionDetailsInfoList, Microsoft.ApplicationInsights.DataContracts.SeverityLevel? severityLevel, string problemId, System.Collections.Generic.IDictionary properties, System.Collections.Generic.IDictionary measurements) -> void Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.HandledAt.get -> Microsoft.ApplicationInsights.DataContracts.ExceptionHandledAt Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.HandledAt.set -> void +Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.ExceptionDetailsInfoList.get -> System.Collections.Generic.IReadOnlyList Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.Message.get -> string Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.Message.set -> void Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.Metrics.get -> System.Collections.Generic.IDictionary @@ -244,6 +254,7 @@ Microsoft.ApplicationInsights.DataContracts.TelemetryContext.InstrumentationKey. Microsoft.ApplicationInsights.DataContracts.TelemetryContext.Location.get -> Microsoft.ApplicationInsights.Extensibility.Implementation.LocationContext Microsoft.ApplicationInsights.DataContracts.TelemetryContext.Operation.get -> Microsoft.ApplicationInsights.Extensibility.Implementation.OperationContext Microsoft.ApplicationInsights.DataContracts.TelemetryContext.Properties.get -> System.Collections.Generic.IDictionary +Microsoft.ApplicationInsights.DataContracts.TelemetryContext.GlobalProperties.get -> System.Collections.Generic.IDictionary Microsoft.ApplicationInsights.DataContracts.TelemetryContext.Session.get -> Microsoft.ApplicationInsights.Extensibility.Implementation.SessionContext Microsoft.ApplicationInsights.DataContracts.TelemetryContext.TelemetryContext() -> void Microsoft.ApplicationInsights.DataContracts.TelemetryContext.User.get -> Microsoft.ApplicationInsights.Extensibility.Implementation.UserContext diff --git a/PublicAPI/Microsoft.ApplicationInsights.dll/net45/PublicAPI.Unshipped.txt b/PublicAPI/Microsoft.ApplicationInsights.dll/net45/PublicAPI.Unshipped.txt index be2d45c507..35653d4cce 100644 --- a/PublicAPI/Microsoft.ApplicationInsights.dll/net45/PublicAPI.Unshipped.txt +++ b/PublicAPI/Microsoft.ApplicationInsights.dll/net45/PublicAPI.Unshipped.txt @@ -1,3 +1,32 @@ +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Id.get -> string +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Id.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Context.get -> Microsoft.ApplicationInsights.DataContracts.TelemetryContext +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.DeepClone() -> Microsoft.ApplicationInsights.Channel.ITelemetry +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.DomProcessing.get -> System.TimeSpan +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.DomProcessing.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Duration.get -> System.TimeSpan +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Duration.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Metrics.get -> System.Collections.Generic.IDictionary +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Name.get -> string +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Name.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.NetworkConnect.get -> System.TimeSpan +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.NetworkConnect.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.PageViewPerformanceTelemetry() -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.PageViewPerformanceTelemetry(string pageName) -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.PerfTotal.get -> System.TimeSpan +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.PerfTotal.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Properties.get -> System.Collections.Generic.IDictionary +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.ReceivedResponse.get -> System.TimeSpan +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.ReceivedResponse.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.SentRequest.get -> System.TimeSpan +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.SentRequest.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Sequence.get -> string +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Sequence.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Timestamp.get -> System.DateTimeOffset +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Timestamp.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Url.get -> System.Uri +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Url.set -> void Microsoft.ApplicationInsights.DataContracts.MetricTelemetry.MetricNamespace.get -> string Microsoft.ApplicationInsights.DataContracts.MetricTelemetry.MetricNamespace.set -> void Microsoft.ApplicationInsights.DataContracts.MetricTelemetry.MetricTelemetry(string metricNamespace, string name, int count, double sum, double min, double max, double standardDeviation) -> void @@ -264,4 +293,63 @@ static readonly Microsoft.ApplicationInsights.MetricConfigurations.Common -> Mic virtual Microsoft.ApplicationInsights.Metrics.MetricConfiguration.Equals(Microsoft.ApplicationInsights.Metrics.MetricConfiguration other) -> bool Microsoft.ApplicationInsights.DataContracts.TelemetryContext.Flags.get -> long Microsoft.ApplicationInsights.DataContracts.TelemetryContext.Flags.set -> void -const Microsoft.ApplicationInsights.DataContracts.TelemetryContext.FlagDropIdentifiers = 2097152 -> long \ No newline at end of file +const Microsoft.ApplicationInsights.DataContracts.TelemetryContext.FlagDropIdentifiers = 2097152 -> long +Microsoft.ApplicationInsights.Channel.ITelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.Channel.ITelemetry.Extension.set -> void +Microsoft.ApplicationInsights.Channel.ITelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.AvailabilityTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.AvailabilityTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.AvailabilityTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.EventTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.EventTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.EventTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.MetricTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.MetricTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.MetricTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.PageViewTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.PageViewTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.PerformanceCounterTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.PerformanceCounterTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.PerformanceCounterTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.SessionStateTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.SessionStateTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.SessionStateTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.TraceTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.TraceTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.TraceTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +override Microsoft.ApplicationInsights.DataContracts.DependencyTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +override Microsoft.ApplicationInsights.DataContracts.DependencyTelemetry.Extension.set -> void +override Microsoft.ApplicationInsights.DataContracts.DependencyTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +override Microsoft.ApplicationInsights.DataContracts.RequestTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +override Microsoft.ApplicationInsights.DataContracts.RequestTelemetry.Extension.set -> void +override Microsoft.ApplicationInsights.DataContracts.RequestTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +abstract Microsoft.ApplicationInsights.Extensibility.Implementation.OperationTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +abstract Microsoft.ApplicationInsights.Extensibility.Implementation.OperationTelemetry.Extension.set -> void +abstract Microsoft.ApplicationInsights.Extensibility.Implementation.OperationTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializableWithWriter +Microsoft.ApplicationInsights.Extensibility.ISerializableWithWriter.Serialize(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.Extensibility.IExtension.DeepClone() -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, string value) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, double? value) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, int? value) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, bool? value) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, System.TimeSpan? value) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, System.DateTimeOffset? value) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, Microsoft.ApplicationInsights.Extensibility.ISerializableWithWriter value) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(Microsoft.ApplicationInsights.Extensibility.ISerializableWithWriter value) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, System.Collections.Generic.IList items) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, System.Collections.Generic.IList items) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, System.Collections.Generic.IDictionary items) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, System.Collections.Generic.IDictionary items) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteStartObject(string name) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteStartObject() -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteEndObject() -> void \ No newline at end of file diff --git a/PublicAPI/Microsoft.ApplicationInsights.dll/net46/PublicAPI.Shipped.txt b/PublicAPI/Microsoft.ApplicationInsights.dll/net46/PublicAPI.Shipped.txt index 916d1e920e..8007a9f1fd 100644 --- a/PublicAPI/Microsoft.ApplicationInsights.dll/net46/PublicAPI.Shipped.txt +++ b/PublicAPI/Microsoft.ApplicationInsights.dll/net46/PublicAPI.Shipped.txt @@ -99,6 +99,14 @@ Microsoft.ApplicationInsights.DataContracts.ExceptionHandledAt Microsoft.ApplicationInsights.DataContracts.ExceptionHandledAt.Platform = 2 -> Microsoft.ApplicationInsights.DataContracts.ExceptionHandledAt Microsoft.ApplicationInsights.DataContracts.ExceptionHandledAt.Unhandled = 0 -> Microsoft.ApplicationInsights.DataContracts.ExceptionHandledAt Microsoft.ApplicationInsights.DataContracts.ExceptionHandledAt.UserCode = 1 -> Microsoft.ApplicationInsights.DataContracts.ExceptionHandledAt +Microsoft.ApplicationInsights.DataContracts.ExceptionDetailsInfo +Microsoft.ApplicationInsights.DataContracts.ExceptionDetailsInfo.ExceptionDetailsInfo(int id, int outerId, string typeName, string message, bool hasFullStack, string stack, System.Collections.Generic.IEnumerable parsedStack) -> void +Microsoft.ApplicationInsights.DataContracts.ExceptionDetailsInfo.TypeName.get -> string +Microsoft.ApplicationInsights.DataContracts.ExceptionDetailsInfo.TypeName.set -> void +Microsoft.ApplicationInsights.DataContracts.ExceptionDetailsInfo.Message.get -> string +Microsoft.ApplicationInsights.DataContracts.ExceptionDetailsInfo.Message.set -> void +Microsoft.ApplicationInsights.DataContracts.StackFrame +Microsoft.ApplicationInsights.DataContracts.StackFrame.StackFrame(string assembly, string fileName, int level, int line, string method) -> void Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.Context.get -> Microsoft.ApplicationInsights.DataContracts.TelemetryContext Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.DeepClone() -> Microsoft.ApplicationInsights.Channel.ITelemetry @@ -106,8 +114,10 @@ Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.Exception.get -> Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.Exception.set -> void Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.ExceptionTelemetry() -> void Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.ExceptionTelemetry(System.Exception exception) -> void +Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.ExceptionTelemetry(System.Collections.Generic.IEnumerable exceptionDetailsInfoList, Microsoft.ApplicationInsights.DataContracts.SeverityLevel? severityLevel, string problemId, System.Collections.Generic.IDictionary properties, System.Collections.Generic.IDictionary measurements) -> void Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.HandledAt.get -> Microsoft.ApplicationInsights.DataContracts.ExceptionHandledAt Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.HandledAt.set -> void +Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.ExceptionDetailsInfoList.get -> System.Collections.Generic.IReadOnlyList Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.Message.get -> string Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.Message.set -> void Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.Metrics.get -> System.Collections.Generic.IDictionary @@ -244,6 +254,7 @@ Microsoft.ApplicationInsights.DataContracts.TelemetryContext.InstrumentationKey. Microsoft.ApplicationInsights.DataContracts.TelemetryContext.Location.get -> Microsoft.ApplicationInsights.Extensibility.Implementation.LocationContext Microsoft.ApplicationInsights.DataContracts.TelemetryContext.Operation.get -> Microsoft.ApplicationInsights.Extensibility.Implementation.OperationContext Microsoft.ApplicationInsights.DataContracts.TelemetryContext.Properties.get -> System.Collections.Generic.IDictionary +Microsoft.ApplicationInsights.DataContracts.TelemetryContext.GlobalProperties.get -> System.Collections.Generic.IDictionary Microsoft.ApplicationInsights.DataContracts.TelemetryContext.Session.get -> Microsoft.ApplicationInsights.Extensibility.Implementation.SessionContext Microsoft.ApplicationInsights.DataContracts.TelemetryContext.TelemetryContext() -> void Microsoft.ApplicationInsights.DataContracts.TelemetryContext.User.get -> Microsoft.ApplicationInsights.Extensibility.Implementation.UserContext diff --git a/PublicAPI/Microsoft.ApplicationInsights.dll/net46/PublicAPI.Unshipped.txt b/PublicAPI/Microsoft.ApplicationInsights.dll/net46/PublicAPI.Unshipped.txt index be2d45c507..35653d4cce 100644 --- a/PublicAPI/Microsoft.ApplicationInsights.dll/net46/PublicAPI.Unshipped.txt +++ b/PublicAPI/Microsoft.ApplicationInsights.dll/net46/PublicAPI.Unshipped.txt @@ -1,3 +1,32 @@ +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Id.get -> string +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Id.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Context.get -> Microsoft.ApplicationInsights.DataContracts.TelemetryContext +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.DeepClone() -> Microsoft.ApplicationInsights.Channel.ITelemetry +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.DomProcessing.get -> System.TimeSpan +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.DomProcessing.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Duration.get -> System.TimeSpan +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Duration.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Metrics.get -> System.Collections.Generic.IDictionary +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Name.get -> string +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Name.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.NetworkConnect.get -> System.TimeSpan +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.NetworkConnect.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.PageViewPerformanceTelemetry() -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.PageViewPerformanceTelemetry(string pageName) -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.PerfTotal.get -> System.TimeSpan +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.PerfTotal.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Properties.get -> System.Collections.Generic.IDictionary +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.ReceivedResponse.get -> System.TimeSpan +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.ReceivedResponse.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.SentRequest.get -> System.TimeSpan +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.SentRequest.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Sequence.get -> string +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Sequence.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Timestamp.get -> System.DateTimeOffset +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Timestamp.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Url.get -> System.Uri +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Url.set -> void Microsoft.ApplicationInsights.DataContracts.MetricTelemetry.MetricNamespace.get -> string Microsoft.ApplicationInsights.DataContracts.MetricTelemetry.MetricNamespace.set -> void Microsoft.ApplicationInsights.DataContracts.MetricTelemetry.MetricTelemetry(string metricNamespace, string name, int count, double sum, double min, double max, double standardDeviation) -> void @@ -264,4 +293,63 @@ static readonly Microsoft.ApplicationInsights.MetricConfigurations.Common -> Mic virtual Microsoft.ApplicationInsights.Metrics.MetricConfiguration.Equals(Microsoft.ApplicationInsights.Metrics.MetricConfiguration other) -> bool Microsoft.ApplicationInsights.DataContracts.TelemetryContext.Flags.get -> long Microsoft.ApplicationInsights.DataContracts.TelemetryContext.Flags.set -> void -const Microsoft.ApplicationInsights.DataContracts.TelemetryContext.FlagDropIdentifiers = 2097152 -> long \ No newline at end of file +const Microsoft.ApplicationInsights.DataContracts.TelemetryContext.FlagDropIdentifiers = 2097152 -> long +Microsoft.ApplicationInsights.Channel.ITelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.Channel.ITelemetry.Extension.set -> void +Microsoft.ApplicationInsights.Channel.ITelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.AvailabilityTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.AvailabilityTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.AvailabilityTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.EventTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.EventTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.EventTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.MetricTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.MetricTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.MetricTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.PageViewTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.PageViewTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.PerformanceCounterTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.PerformanceCounterTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.PerformanceCounterTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.SessionStateTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.SessionStateTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.SessionStateTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.TraceTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.TraceTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.TraceTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +override Microsoft.ApplicationInsights.DataContracts.DependencyTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +override Microsoft.ApplicationInsights.DataContracts.DependencyTelemetry.Extension.set -> void +override Microsoft.ApplicationInsights.DataContracts.DependencyTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +override Microsoft.ApplicationInsights.DataContracts.RequestTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +override Microsoft.ApplicationInsights.DataContracts.RequestTelemetry.Extension.set -> void +override Microsoft.ApplicationInsights.DataContracts.RequestTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +abstract Microsoft.ApplicationInsights.Extensibility.Implementation.OperationTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +abstract Microsoft.ApplicationInsights.Extensibility.Implementation.OperationTelemetry.Extension.set -> void +abstract Microsoft.ApplicationInsights.Extensibility.Implementation.OperationTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializableWithWriter +Microsoft.ApplicationInsights.Extensibility.ISerializableWithWriter.Serialize(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.Extensibility.IExtension.DeepClone() -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, string value) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, double? value) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, int? value) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, bool? value) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, System.TimeSpan? value) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, System.DateTimeOffset? value) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, Microsoft.ApplicationInsights.Extensibility.ISerializableWithWriter value) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(Microsoft.ApplicationInsights.Extensibility.ISerializableWithWriter value) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, System.Collections.Generic.IList items) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, System.Collections.Generic.IList items) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, System.Collections.Generic.IDictionary items) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, System.Collections.Generic.IDictionary items) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteStartObject(string name) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteStartObject() -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteEndObject() -> void \ No newline at end of file diff --git a/PublicAPI/Microsoft.ApplicationInsights.dll/netstandard1.3/PublicAPI.Shipped.txt b/PublicAPI/Microsoft.ApplicationInsights.dll/netstandard1.3/PublicAPI.Shipped.txt index 0994669abc..8f5b72affe 100644 --- a/PublicAPI/Microsoft.ApplicationInsights.dll/netstandard1.3/PublicAPI.Shipped.txt +++ b/PublicAPI/Microsoft.ApplicationInsights.dll/netstandard1.3/PublicAPI.Shipped.txt @@ -99,6 +99,14 @@ Microsoft.ApplicationInsights.DataContracts.ExceptionHandledAt Microsoft.ApplicationInsights.DataContracts.ExceptionHandledAt.Platform = 2 -> Microsoft.ApplicationInsights.DataContracts.ExceptionHandledAt Microsoft.ApplicationInsights.DataContracts.ExceptionHandledAt.Unhandled = 0 -> Microsoft.ApplicationInsights.DataContracts.ExceptionHandledAt Microsoft.ApplicationInsights.DataContracts.ExceptionHandledAt.UserCode = 1 -> Microsoft.ApplicationInsights.DataContracts.ExceptionHandledAt +Microsoft.ApplicationInsights.DataContracts.ExceptionDetailsInfo +Microsoft.ApplicationInsights.DataContracts.ExceptionDetailsInfo.ExceptionDetailsInfo(int id, int outerId, string typeName, string message, bool hasFullStack, string stack, System.Collections.Generic.IEnumerable parsedStack) -> void +Microsoft.ApplicationInsights.DataContracts.ExceptionDetailsInfo.TypeName.get -> string +Microsoft.ApplicationInsights.DataContracts.ExceptionDetailsInfo.TypeName.set -> void +Microsoft.ApplicationInsights.DataContracts.ExceptionDetailsInfo.Message.get -> string +Microsoft.ApplicationInsights.DataContracts.ExceptionDetailsInfo.Message.set -> void +Microsoft.ApplicationInsights.DataContracts.StackFrame +Microsoft.ApplicationInsights.DataContracts.StackFrame.StackFrame(string assembly, string fileName, int level, int line, string method) -> void Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.Context.get -> Microsoft.ApplicationInsights.DataContracts.TelemetryContext Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.DeepClone() -> Microsoft.ApplicationInsights.Channel.ITelemetry @@ -106,8 +114,10 @@ Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.Exception.get -> Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.Exception.set -> void Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.ExceptionTelemetry() -> void Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.ExceptionTelemetry(System.Exception exception) -> void +Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.ExceptionTelemetry(System.Collections.Generic.IEnumerable exceptionDetailsInfoList, Microsoft.ApplicationInsights.DataContracts.SeverityLevel? severityLevel, string problemId, System.Collections.Generic.IDictionary properties, System.Collections.Generic.IDictionary measurements) -> void Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.HandledAt.get -> Microsoft.ApplicationInsights.DataContracts.ExceptionHandledAt Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.HandledAt.set -> void +Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.ExceptionDetailsInfoList.get -> System.Collections.Generic.IReadOnlyList Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.Message.get -> string Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.Message.set -> void Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.Metrics.get -> System.Collections.Generic.IDictionary @@ -243,6 +253,7 @@ Microsoft.ApplicationInsights.DataContracts.TelemetryContext.InstrumentationKey. Microsoft.ApplicationInsights.DataContracts.TelemetryContext.Location.get -> Microsoft.ApplicationInsights.Extensibility.Implementation.LocationContext Microsoft.ApplicationInsights.DataContracts.TelemetryContext.Operation.get -> Microsoft.ApplicationInsights.Extensibility.Implementation.OperationContext Microsoft.ApplicationInsights.DataContracts.TelemetryContext.Properties.get -> System.Collections.Generic.IDictionary +Microsoft.ApplicationInsights.DataContracts.TelemetryContext.GlobalProperties.get -> System.Collections.Generic.IDictionary Microsoft.ApplicationInsights.DataContracts.TelemetryContext.Session.get -> Microsoft.ApplicationInsights.Extensibility.Implementation.SessionContext Microsoft.ApplicationInsights.DataContracts.TelemetryContext.TelemetryContext() -> void Microsoft.ApplicationInsights.DataContracts.TelemetryContext.User.get -> Microsoft.ApplicationInsights.Extensibility.Implementation.UserContext diff --git a/PublicAPI/Microsoft.ApplicationInsights.dll/netstandard1.3/PublicAPI.Unshipped.txt b/PublicAPI/Microsoft.ApplicationInsights.dll/netstandard1.3/PublicAPI.Unshipped.txt index 031af31ff3..19c24ee0d5 100644 --- a/PublicAPI/Microsoft.ApplicationInsights.dll/netstandard1.3/PublicAPI.Unshipped.txt +++ b/PublicAPI/Microsoft.ApplicationInsights.dll/netstandard1.3/PublicAPI.Unshipped.txt @@ -1,3 +1,32 @@ +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Id.get -> string +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Id.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Context.get -> Microsoft.ApplicationInsights.DataContracts.TelemetryContext +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.DeepClone() -> Microsoft.ApplicationInsights.Channel.ITelemetry +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.DomProcessing.get -> System.TimeSpan +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.DomProcessing.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Duration.get -> System.TimeSpan +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Duration.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Metrics.get -> System.Collections.Generic.IDictionary +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Name.get -> string +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Name.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.NetworkConnect.get -> System.TimeSpan +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.NetworkConnect.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.PageViewPerformanceTelemetry() -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.PageViewPerformanceTelemetry(string pageName) -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.PerfTotal.get -> System.TimeSpan +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.PerfTotal.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Properties.get -> System.Collections.Generic.IDictionary +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.ReceivedResponse.get -> System.TimeSpan +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.ReceivedResponse.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.SentRequest.get -> System.TimeSpan +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.SentRequest.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Sequence.get -> string +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Sequence.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Timestamp.get -> System.DateTimeOffset +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Timestamp.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Url.get -> System.Uri +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Url.set -> void Microsoft.ApplicationInsights.DataContracts.MetricTelemetry.MetricNamespace.get -> string Microsoft.ApplicationInsights.DataContracts.MetricTelemetry.MetricNamespace.set -> void Microsoft.ApplicationInsights.DataContracts.MetricTelemetry.MetricTelemetry(string metricNamespace, string name, int count, double sum, double min, double max, double standardDeviation) -> void @@ -265,4 +294,63 @@ virtual Microsoft.ApplicationInsights.Metrics.MetricConfiguration.Equals(Microso Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.SetParsedStack(System.Diagnostics.StackFrame[] frames) -> void Microsoft.ApplicationInsights.DataContracts.TelemetryContext.Flags.get -> long Microsoft.ApplicationInsights.DataContracts.TelemetryContext.Flags.set -> void -const Microsoft.ApplicationInsights.DataContracts.TelemetryContext.FlagDropIdentifiers = 2097152 -> long \ No newline at end of file +const Microsoft.ApplicationInsights.DataContracts.TelemetryContext.FlagDropIdentifiers = 2097152 -> long +Microsoft.ApplicationInsights.Channel.ITelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.Channel.ITelemetry.Extension.set -> void +Microsoft.ApplicationInsights.Channel.ITelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.AvailabilityTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.AvailabilityTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.AvailabilityTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.EventTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.EventTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.EventTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.MetricTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.MetricTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.MetricTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewPerformanceTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.PageViewTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.PageViewTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.PageViewTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.PerformanceCounterTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.PerformanceCounterTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.PerformanceCounterTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.SessionStateTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.SessionStateTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.SessionStateTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.DataContracts.TraceTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.DataContracts.TraceTelemetry.Extension.set -> void +Microsoft.ApplicationInsights.DataContracts.TraceTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +override Microsoft.ApplicationInsights.DataContracts.DependencyTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +override Microsoft.ApplicationInsights.DataContracts.DependencyTelemetry.Extension.set -> void +override Microsoft.ApplicationInsights.DataContracts.DependencyTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +override Microsoft.ApplicationInsights.DataContracts.RequestTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +override Microsoft.ApplicationInsights.DataContracts.RequestTelemetry.Extension.set -> void +override Microsoft.ApplicationInsights.DataContracts.RequestTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +abstract Microsoft.ApplicationInsights.Extensibility.Implementation.OperationTelemetry.Extension.get -> Microsoft.ApplicationInsights.Extensibility.IExtension +abstract Microsoft.ApplicationInsights.Extensibility.Implementation.OperationTelemetry.Extension.set -> void +abstract Microsoft.ApplicationInsights.Extensibility.Implementation.OperationTelemetry.SerializeData(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializableWithWriter +Microsoft.ApplicationInsights.Extensibility.ISerializableWithWriter.Serialize(Microsoft.ApplicationInsights.Extensibility.ISerializationWriter serializationWriter) -> void +Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.Extensibility.IExtension.DeepClone() -> Microsoft.ApplicationInsights.Extensibility.IExtension +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, string value) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, double? value) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, int? value) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, bool? value) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, System.TimeSpan? value) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, System.DateTimeOffset? value) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, Microsoft.ApplicationInsights.Extensibility.ISerializableWithWriter value) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(Microsoft.ApplicationInsights.Extensibility.ISerializableWithWriter value) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, System.Collections.Generic.IList items) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, System.Collections.Generic.IList items) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, System.Collections.Generic.IDictionary items) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteProperty(string name, System.Collections.Generic.IDictionary items) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteStartObject(string name) -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteStartObject() -> void +Microsoft.ApplicationInsights.Extensibility.ISerializationWriter.WriteEndObject() -> void \ No newline at end of file diff --git a/Test/Microsoft.ApplicationInsights.Test/Shared/Channel/ITelemetryTest.cs b/Test/Microsoft.ApplicationInsights.Test/Shared/Channel/ITelemetryTest.cs index 536871a9c5..623ec6152b 100644 --- a/Test/Microsoft.ApplicationInsights.Test/Shared/Channel/ITelemetryTest.cs +++ b/Test/Microsoft.ApplicationInsights.Test/Shared/Channel/ITelemetryTest.cs @@ -6,6 +6,8 @@ using Microsoft.ApplicationInsights.DataContracts; using AI; using Microsoft.VisualStudio.TestTools.UnitTesting; + using Microsoft.ApplicationInsights.Extensibility; + using Microsoft.ApplicationInsights.Extensibility.Implementation; internal class ITelemetryTest where TTelemetry : ITelemetry, new() @@ -18,6 +20,7 @@ public void Run() this.ClassShouldHaveParameterizedConstructorToSimplifyCreationOfValidTelemetryInstancesInUserCode(); this.ClassShouldImplementISupportCustomPropertiesIfItDefinesPropertiesProperty(); this.TestProperties(); + this.TestExtension(); this.SerializeWritesTimestampAsExpectedByEndpoint(); this.SerializeWritesSequenceAsExpectedByEndpoint(); this.SerializeWritesInstrumentationKeyAsExpectedByEndpoint(); @@ -25,6 +28,22 @@ public void Run() this.SerializeWritesDataBaseTypeAsExpectedByEndpoint(); } + private void TestExtension() + { + // Extention field exists + var extensionField = typeof(TTelemetry).GetRuntimeProperties().Any(p => p.Name == "Extension"); + Assert.IsNotNull(extensionField); + + TTelemetry tel = new TTelemetry(); + Assert.IsNull(tel.Extension, "Extension should be null by default"); + + // Set extension + var myExt = new MyTestExtension(); + tel.Extension = myExt; + + Assert.AreSame(myExt, tel.Extension, "Extension should be assignable."); + } + private void TestProperties() { foreach (PropertyInfo property in typeof(TTelemetry).GetRuntimeProperties()) @@ -215,6 +234,11 @@ private string ExtractTelemetryNameFromType(Type telemetryType) // handle TraceTelemetry separately result = "Message"; } + else if (telemetryType == typeof(DependencyTelemetry)) + { + // handle DeppendencyTelemetry separately + result = "RemoteDependency"; + } #pragma warning disable 618 else if (telemetryType == typeof(SessionStateTelemetry)) { diff --git a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/AvailabilityTelemetryTest.cs b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/AvailabilityTelemetryTest.cs index 0da956a2a7..a6917e163d 100644 --- a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/AvailabilityTelemetryTest.cs +++ b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/AvailabilityTelemetryTest.cs @@ -147,6 +147,15 @@ public void AvailabilityTelemetryDeepCloneCopiesAllProperties() Assert.IsTrue(result.AreEqual, result.DifferencesString); } + [TestMethod] + public void AvailabilityTelemetryDeepCloneWithNullExtensionDoesNotThrow() + { + var telemetry = new AvailabilityTelemetry(); + // Extension is not set, means it'll be null. + // Validate that cloning with null Extension does not throw. + var other = telemetry.DeepClone(); + } + private AvailabilityTelemetry CreateAvailabilityTelemetry() { AvailabilityTelemetry item = new AvailabilityTelemetry @@ -161,7 +170,7 @@ private AvailabilityTelemetry CreateAvailabilityTelemetry() item.Properties.Add("TestProperty", "TestValue"); item.Context.GlobalProperties.Add("TestPropertyGlobal", "TestValue"); item.Sequence = "12"; - + item.Extension = new MyTestExtension(); return item; } diff --git a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/DependencyTelemetryTest.cs b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/DependencyTelemetryTest.cs index 246bbe16c5..4334d1575e 100644 --- a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/DependencyTelemetryTest.cs +++ b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/DependencyTelemetryTest.cs @@ -2,6 +2,8 @@ { using System; using System.Collections.Generic; + using System.Globalization; + using System.IO; using System.Linq; using KellermanSoftware.CompareNetObjects; using Microsoft.ApplicationInsights.Channel; @@ -23,6 +25,12 @@ public void VerifyExpectedDefaultValue() Assert.AreEqual(true, defaultDependencyTelemetry.Success, "Success is expected to be true"); } + [TestMethod] + public void DependencyTelemetryITelemetryContractConsistentlyWithOtherTelemetryTypes() + { + new ITelemetryTest().Run(); + } + [TestMethod] public void DependencyTelemetryPropertiesFromContextAndItemSerializesToPropertiesInJson() { @@ -80,6 +88,24 @@ public void SerializeWritesNullValuesAsExpectedByEndpoint() Assert.AreEqual(2, item.data.baseData.ver); } + [TestMethod] + public void SerializePopulatesRequiredFieldsOfDependencyTelemetry() + { + using (StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture)) + { + var depTelemetry = new DependencyTelemetry(); + depTelemetry.Context.InstrumentationKey = Guid.NewGuid().ToString(); + ((ITelemetry)depTelemetry).Sanitize(); + var item = TelemetryItemTestHelper.SerializeDeserializeTelemetryItem(depTelemetry); + + Assert.AreEqual(2, item.data.baseData.ver); + Assert.IsNotNull(item.data.baseData.id); + Assert.IsNotNull(item.time); + Assert.AreEqual(new TimeSpan(), TimeSpan.Parse(item.data.baseData.duration)); + Assert.IsTrue(item.data.baseData.success); + } + } + [TestMethod] public void RemoteDependencyTelemetrySerializesStructuredIKeyToJsonCorrectlyPreservingPrefixCasing() { @@ -218,7 +244,6 @@ public void DependencyTelemetryGetUnsetOperationDetail() telemetry.ClearOperationDetails(); } -#if !NETCOREAPP1_1 [TestMethod] public void DependencyTelemetryDeepCloneCopiesAllProperties() { @@ -231,7 +256,15 @@ public void DependencyTelemetryDeepCloneCopiesAllProperties() ComparisonResult result = deepComparator.Compare(telemetry, other); Assert.IsTrue(result.AreEqual, result.DifferencesString); } -#endif + + [TestMethod] + public void DependencyTelemetryDeepCloneWithNullExtensionDoesNotThrow() + { + var telemetry = new DependencyTelemetry(); + // Extension is not set, means it'll be null. + // Validate that cloning with null Extension does not throw. + var other = telemetry.DeepClone(); + } private DependencyTelemetry CreateRemoteDependencyTelemetry() { @@ -249,7 +282,7 @@ private DependencyTelemetry CreateRemoteDependencyTelemetry() item.Context.InstrumentationKey = Guid.NewGuid().ToString(); item.Properties.Add("TestProperty", "TestValue"); item.Context.GlobalProperties.Add("TestPropertyGlobal", "TestValue"); - + item.Extension = new MyTestExtension(); return item; } diff --git a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/EventTelemetryTest.cs b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/EventTelemetryTest.cs index 6014c5a47b..137393da17 100644 --- a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/EventTelemetryTest.cs +++ b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/EventTelemetryTest.cs @@ -153,6 +153,7 @@ public void EventTelemetryDeepCloneCopiesAllProperties() eventTelemetry.Name = "Test Event"; eventTelemetry.Properties["Test Property"] = "Test Value"; eventTelemetry.Metrics["Test Property"] = 4.2; + eventTelemetry.Extension = new MyTestExtension(); EventTelemetry other = (EventTelemetry)eventTelemetry.DeepClone(); CompareLogic deepComparator = new CompareLogic(); @@ -161,6 +162,15 @@ public void EventTelemetryDeepCloneCopiesAllProperties() Assert.IsTrue(result.AreEqual, result.DifferencesString); } + [TestMethod] + public void EventTelemetryDeepCloneWithNullExtensionDoesNotThrow() + { + var telemetry = new EventTelemetry(); + // Extension is not set, means it'll be null. + // Validate that cloning with null Extension does not throw. + var other = telemetry.DeepClone(); + } + [TestMethod] public void EventTelemetryHasCorrectValueOfSamplingPercentageAfterSerialization() { diff --git a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/ExceptionTelemetryTest.cs b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/ExceptionTelemetryTest.cs index ebe4bb9f6e..2ac3483b1e 100644 --- a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/ExceptionTelemetryTest.cs +++ b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/ExceptionTelemetryTest.cs @@ -39,6 +39,122 @@ public void ExceptionTelemetryReturnsNonNullContext() Assert.IsNotNull(item.Context); } + [TestMethod] + public void ExceptionTelemetryCreatedBasedOnCustomData() + { + // ARRANGE + var topLevelexceptionDetails = new ExceptionDetailsInfo(1, -1, "TopLevelException", "Top level exception", + true, "Top level exception stack", new[] + { + new StackFrame("Some.Assembly", "SomeFile.dll", 3, 33, "TopLevelMethod"), + new StackFrame("Some.Assembly", "SomeOtherFile.dll", 2, 22, "LowerLevelMethod"), + new StackFrame("Some.Assembly", "YetAnotherFile.dll", 1, 11, "LowLevelMethod") + }); + + var innerExceptionDetails = new ExceptionDetailsInfo(2, 1, "InnerException", "Inner exception", false, + "Inner exception stack", new[] + { + new StackFrame("Some.Assembly", "ImportantFile.dll", 2, 22, "InnerMethod"), + new StackFrame("Some.Assembly", "LessImportantFile.dll", 1, 11, "DeeperInnerMethod") + }); + + // ACT + ExceptionTelemetry item = new ExceptionTelemetry(new[] {topLevelexceptionDetails, innerExceptionDetails}, + SeverityLevel.Error, "ProblemId", + new Dictionary() {["property1"] = "value1", ["property2"] = "value2"}, + new Dictionary() {["property1"] = 1, ["property2"] = 2}); + + item.ExceptionDetailsInfoList[1].Message = "Inner exception modified"; + item.ProblemId = "ProblemId modified"; + + // ASSERT + // use internal fields to validate + Assert.AreEqual(item.Data.Data.ver, 2); + Assert.AreEqual(item.Data.Data.problemId, "ProblemId modified"); + Assert.AreEqual(item.Data.Data.severityLevel, Extensibility.Implementation.External.SeverityLevel.Error); + + Assert.AreEqual(item.Data.Data.properties.Count, 2); + Assert.IsTrue(item.Data.Data.properties.Keys.Contains("property1")); + Assert.IsTrue(item.Data.Data.properties.Keys.Contains("property2")); + Assert.IsTrue(item.Data.Data.properties.Values.Contains("value1")); + Assert.IsTrue(item.Data.Data.properties.Values.Contains("value2")); + + Assert.AreEqual(item.Data.Data.measurements.Count, 2); + Assert.IsTrue(item.Data.Data.measurements.Keys.Contains("property1")); + Assert.IsTrue(item.Data.Data.measurements.Keys.Contains("property2")); + Assert.IsTrue(item.Data.Data.measurements.Values.Contains(1)); + Assert.IsTrue(item.Data.Data.measurements.Values.Contains(2)); + + Assert.AreEqual(item.Data.Data.exceptions.Count, 2); + + Assert.AreEqual(item.Data.Data.exceptions.First().id, 1); + Assert.AreEqual(item.Data.Data.exceptions.First().outerId, -1); + Assert.AreEqual(item.Data.Data.exceptions.First().typeName, "TopLevelException"); + Assert.AreEqual(item.Data.Data.exceptions.First().message, "Top level exception"); + Assert.AreEqual(item.Data.Data.exceptions.First().hasFullStack, true); + Assert.AreEqual(item.Data.Data.exceptions.First().stack, "Top level exception stack"); + Assert.AreEqual(item.Data.Data.exceptions.First().parsedStack.Count, 3); + + Assert.AreEqual(item.Data.Data.exceptions.First().parsedStack[0].assembly, "Some.Assembly"); + Assert.AreEqual(item.Data.Data.exceptions.First().parsedStack[0].fileName, "SomeFile.dll"); + Assert.AreEqual(item.Data.Data.exceptions.First().parsedStack[0].level, 3); + Assert.AreEqual(item.Data.Data.exceptions.First().parsedStack[0].line, 33); + Assert.AreEqual(item.Data.Data.exceptions.First().parsedStack[0].method, "TopLevelMethod"); + + Assert.AreEqual(item.Data.Data.exceptions.First().parsedStack[1].assembly, "Some.Assembly"); + Assert.AreEqual(item.Data.Data.exceptions.First().parsedStack[1].fileName, "SomeOtherFile.dll"); + Assert.AreEqual(item.Data.Data.exceptions.First().parsedStack[1].level, 2); + Assert.AreEqual(item.Data.Data.exceptions.First().parsedStack[1].line, 22); + Assert.AreEqual(item.Data.Data.exceptions.First().parsedStack[1].method, "LowerLevelMethod"); + + Assert.AreEqual(item.Data.Data.exceptions.First().parsedStack[2].assembly, "Some.Assembly"); + Assert.AreEqual(item.Data.Data.exceptions.First().parsedStack[2].fileName, "YetAnotherFile.dll"); + Assert.AreEqual(item.Data.Data.exceptions.First().parsedStack[2].level, 1); + Assert.AreEqual(item.Data.Data.exceptions.First().parsedStack[2].line, 11); + Assert.AreEqual(item.Data.Data.exceptions.First().parsedStack[2].method, "LowLevelMethod"); + + Assert.AreEqual(item.Data.Data.exceptions.Last().id, 2); + Assert.AreEqual(item.Data.Data.exceptions.Last().outerId, 1); + Assert.AreEqual(item.Data.Data.exceptions.Last().typeName, "InnerException"); + Assert.AreEqual(item.Data.Data.exceptions.Last().message, "Inner exception modified"); + Assert.AreEqual(item.Data.Data.exceptions.Last().hasFullStack, false); + Assert.AreEqual(item.Data.Data.exceptions.Last().stack, "Inner exception stack"); + Assert.AreEqual(item.Data.Data.exceptions.Last().parsedStack.Count, 2); + + Assert.AreEqual(item.Data.Data.exceptions.Last().parsedStack[0].assembly, "Some.Assembly"); + Assert.AreEqual(item.Data.Data.exceptions.Last().parsedStack[0].fileName, "ImportantFile.dll"); + Assert.AreEqual(item.Data.Data.exceptions.Last().parsedStack[0].level, 2); + Assert.AreEqual(item.Data.Data.exceptions.Last().parsedStack[0].line, 22); + Assert.AreEqual(item.Data.Data.exceptions.Last().parsedStack[0].method, "InnerMethod"); + + Assert.AreEqual(item.Data.Data.exceptions.Last().parsedStack[1].assembly, "Some.Assembly"); + Assert.AreEqual(item.Data.Data.exceptions.Last().parsedStack[1].fileName, "LessImportantFile.dll"); + Assert.AreEqual(item.Data.Data.exceptions.Last().parsedStack[1].level, 1); + Assert.AreEqual(item.Data.Data.exceptions.Last().parsedStack[1].line, 11); + Assert.AreEqual(item.Data.Data.exceptions.Last().parsedStack[1].method, "DeeperInnerMethod"); + } + + [TestMethod] + public void ExceptionTelemetryExceptionDetailsUpdate() + { + // ARRANGE + var exception = new AggregateException("Test Exception", new Exception()); + ExceptionTelemetry item = new ExceptionTelemetry(exception); + + // ACT + IReadOnlyList newExceptionDetails = item.ExceptionDetailsInfoList; + + string modifiedMessage = "Modified Message"; + string modifiedTypeName = "Modified TypeName"; + + newExceptionDetails[0].Message = modifiedMessage; + newExceptionDetails[0].TypeName = modifiedTypeName; + + // ASSERT + Assert.AreEqual(modifiedMessage, item.Exceptions[0].message); + Assert.AreEqual(modifiedTypeName, item.Exceptions[0].typeName); + } + [TestMethod] public void ExceptionsPropertyIsInternalUntilWeSortOutPublicInterface() { @@ -53,6 +169,7 @@ public void ConstructorAddsExceptionToExceptionPropertyAndExceptionsCollectionPr Assert.AreSame(constructorException, testExceptionTelemetry.Exception); Assert.AreEqual(constructorException.Message, testExceptionTelemetry.Exceptions.First().message); + Assert.AreEqual(constructorException.Message, testExceptionTelemetry.ExceptionDetailsInfoList.First().Message); } [TestMethod] @@ -66,6 +183,7 @@ public void ExceptionPropertySetterReplacesExceptionDetailsInExceptionsCollectio Assert.AreSame(nextException, testExceptionTelemetry.Exception); Assert.AreEqual(nextException.Message, testExceptionTelemetry.Exceptions.First().message); + Assert.AreEqual(nextException.Message, testExceptionTelemetry.ExceptionDetailsInfoList.First().Message); } #pragma warning disable 618 @@ -344,9 +462,12 @@ public void ExceptionPropertySetterHandlesAggregateExceptionsWithMultipleNestedE }; Assert.AreEqual(expectedSequence.Length, telemetry.Exceptions.Count); - int counter = 0; - foreach (ExceptionDetails details in telemetry.Exceptions) + Assert.AreEqual(expectedSequence.Length, telemetry.ExceptionDetailsInfoList.Count); + for(int counter = 0; counter < expectedSequence.Length; counter++) { + ExceptionDetails details = telemetry.Exceptions[counter]; + ExceptionDetailsInfo newExceptionDetails = telemetry.ExceptionDetailsInfoList[counter]; + Assert.IsTrue(ReferenceEquals(details, newExceptionDetails.InternalExceptionDetails)); if (details.typeName == "System.AggregateException") { AssertEx.StartsWith(expectedSequence[counter], details.message); @@ -355,7 +476,6 @@ public void ExceptionPropertySetterHandlesAggregateExceptionsWithMultipleNestedE { Assert.AreEqual(expectedSequence[counter], details.message); } - counter++; } } @@ -374,9 +494,12 @@ public void ExceptionPropertySetterHandlesAggregateExceptionsWithMultipleNestedE ExceptionTelemetry telemetry = new ExceptionTelemetry { Exception = rootLevelException }; Assert.AreEqual(Constants.MaxExceptionCountToSave + 1, telemetry.Exceptions.Count); - int counter = 0; - foreach (ExceptionDetails details in telemetry.Exceptions.Take(Constants.MaxExceptionCountToSave)) + Assert.AreEqual(Constants.MaxExceptionCountToSave + 1, telemetry.ExceptionDetailsInfoList.Count); + for(int counter = 0; counter < Constants.MaxExceptionCountToSave; counter++) { + ExceptionDetails details = telemetry.Exceptions[counter]; + ExceptionDetailsInfo newExceptionDetails = telemetry.ExceptionDetailsInfoList[counter]; + Assert.IsTrue(ReferenceEquals(details, newExceptionDetails.InternalExceptionDetails)); if (details.typeName == "System.AggregateException") { AssertEx.StartsWith(counter.ToString(CultureInfo.InvariantCulture), details.message); @@ -385,7 +508,6 @@ public void ExceptionPropertySetterHandlesAggregateExceptionsWithMultipleNestedE { Assert.AreEqual(counter.ToString(CultureInfo.InvariantCulture), details.message); } - counter++; } ExceptionDetails first = telemetry.Exceptions.First(); @@ -465,6 +587,15 @@ public void ExceptionTelemetryDeepCloneCopiesAllProperties() Assert.IsTrue(result.AreEqual, result.DifferencesString); } + [TestMethod] + public void ExceptionTelemetryDeepCloneWithNullExtensionDoesNotThrow() + { + var telemetry = new ExceptionTelemetry(); + // Extension is not set, means it'll be null. + // Validate that cloning with null Extension does not throw. + var other = telemetry.DeepClone(); + } + [TestMethod] public void ExceptionTelemetryPropertiesFromContextAndItemSerializesToPropertiesInJson() { @@ -508,6 +639,7 @@ private static ExceptionTelemetry CreateExceptionTelemetry(Exception exception = output.Context.GlobalProperties.Add("TestPropertyGlobal", "contextpropvalue"); output.Context.InstrumentationKey = "required"; output.Properties.Add("TestProperty", "TestPropertyValue"); + output.Extension = new MyTestExtension(); return output; } } diff --git a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/MetricTelemetryTest.cs b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/MetricTelemetryTest.cs index b04132e065..82213c309f 100644 --- a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/MetricTelemetryTest.cs +++ b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/MetricTelemetryTest.cs @@ -27,7 +27,7 @@ public void MetricTelemetryImplementsITelemetryContract() } [TestMethod] - public void EventTelemetryReturnsNonNullContext() + public void MetricTelemetryReturnsNonNullContext() { MetricTelemetry item = new MetricTelemetry(); Assert.IsNotNull(item.Context); @@ -355,12 +355,21 @@ public void MetricTelemetryDeepCloneCopiesAllProperties() metric.Max = 6.4; metric.StandardDeviation = 0.5; metric.Properties.Add("Property1", "Value1"); - + metric.Extension = new MyTestExtension(); MetricTelemetry other = (MetricTelemetry)metric.DeepClone(); CompareLogic deepComparator = new CompareLogic(); var comparisonResult = deepComparator.Compare(metric, other); Assert.IsTrue(comparisonResult.AreEqual, comparisonResult.DifferencesString); } + + [TestMethod] + public void MetricTelemetryDeepCloneWithNullExtensionDoesNotThrow() + { + var telemetry = new MetricTelemetry(); + // Extension is not set, means it'll be null. + // Validate that cloning with null Extension does not throw. + var other = telemetry.DeepClone(); + } } } diff --git a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/PageViewPerformanceTelemetryTest.cs b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/PageViewPerformanceTelemetryTest.cs new file mode 100644 index 0000000000..cd668cbe5a --- /dev/null +++ b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/PageViewPerformanceTelemetryTest.cs @@ -0,0 +1,209 @@ +namespace Microsoft.ApplicationInsights.DataContracts +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.IO; + using System.Linq; + using System.Reflection; + using Microsoft.ApplicationInsights.Channel; + using Microsoft.ApplicationInsights.Extensibility; + using Microsoft.ApplicationInsights.Extensibility.Implementation; + using Microsoft.ApplicationInsights.TestFramework; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using CompareLogic = KellermanSoftware.CompareNetObjects.CompareLogic; + + + [TestClass] + public class PageViewPerformanceTelemetryTest + { + [TestMethod] + public void PageViewImplementsITelemetryContractConsistentlyWithOtherTelemetryTypes() + { + new ITelemetryTest().Run(); + } + + [TestMethod] + public void PageViewPerformanceTelemetryIsPublic() + { + Assert.IsTrue(typeof(PageViewPerformanceTelemetry).GetTypeInfo().IsPublic); + } + + [TestMethod] + public void PageViewPerformanceTelemetryReturnsNonNullContext() + { + PageViewPerformanceTelemetry item = new PageViewPerformanceTelemetry(); + Assert.IsNotNull(item.Context); + } + + [TestMethod] + public void PageViewPerformanceTelemetrySuppliesConstructorThatTakesNameParameter() + { + string expectedPageName = "My page view"; + var instance = new PageViewPerformanceTelemetry(expectedPageName); + Assert.AreEqual(expectedPageName, instance.Name); + } + + [TestMethod] + public void PageViewPerformanceTelemetryReturnsDefaultDurationAsTimespanZero() + { + PageViewPerformanceTelemetry item = new PageViewPerformanceTelemetry(); + Assert.AreEqual(TimeSpan.Zero, item.Duration); + } + + [TestMethod] + public void PageViewPerformanceTelemetrySerializesToJsonCorrectly() + { + var expected = new PageViewPerformanceTelemetry("My Page"); + expected.Url = new Uri("http://temp.org/page1"); + expected.Duration = TimeSpan.FromSeconds(123); + expected.Metrics.Add("Metric1", 30); + expected.Properties.Add("Property1", "Value1"); + + var item = TelemetryItemTestHelper.SerializeDeserializeTelemetryItem(expected); + + // NOTE: It's correct that we use the v1 name here, and therefore we test against it. + Assert.AreEqual(item.name, AI.ItemType.PageViewPerformance); + + Assert.AreEqual(PageViewPerformanceTelemetry.BaseType, item.data.baseType); + Assert.AreEqual(2, item.data.baseData.ver); + Assert.AreEqual(expected.Name, item.data.baseData.name); + Assert.AreEqual(expected.Duration, TimeSpan.Parse(item.data.baseData.duration)); + Assert.AreEqual(expected.Url.ToString(), item.data.baseData.url); + + AssertEx.AreEqual(expected.Properties.ToArray(), item.data.baseData.properties.ToArray()); + } + + [TestMethod] + public void PageViewPerformanceTelemetryTelemetryPropertiesFromContextAndItemSerializesToPropertiesInJson() + { + var expected = new PageViewPerformanceTelemetry(); + expected.Context.GlobalProperties.Add("TestPropertyGlobal", "contextpropvalue"); + expected.Properties.Add("TestProperty", "TestPropertyValue"); + ((ITelemetry)expected).Sanitize(); + + Assert.AreEqual(1, expected.Properties.Count); + Assert.AreEqual(1, expected.Context.GlobalProperties.Count); + + Assert.IsTrue(expected.Properties.ContainsKey("TestProperty")); + Assert.IsTrue(expected.Context.GlobalProperties.ContainsKey("TestPropertyGlobal")); + + var item = TelemetryItemTestHelper.SerializeDeserializeTelemetryItem(expected); + + // Items added to both PageViewPerformanceTelemetry.Properties, and PageViewPerformanceTelemetry.Context.GlobalProperties are serialized to properties. + Assert.AreEqual(2, item.data.baseData.properties.Count); + Assert.IsTrue(item.data.baseData.properties.ContainsKey("TestPropertyGlobal")); + Assert.IsTrue(item.data.baseData.properties.ContainsKey("TestProperty")); + } + + [TestMethod] + public void SerializePopulatesRequiredFieldsOfPageViewPerfTelemetry() + { + using (StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture)) + { + var pvTelemetry = new PageViewPerformanceTelemetry(); + pvTelemetry.Context.InstrumentationKey = Guid.NewGuid().ToString(); + ((ITelemetry)pvTelemetry).Sanitize(); + var item = TelemetryItemTestHelper.SerializeDeserializeTelemetryItem(pvTelemetry); + + Assert.AreEqual(2, item.data.baseData.ver); + Assert.IsNotNull(item.data.baseData.id); + Assert.IsNotNull(item.time); + Assert.AreEqual(new TimeSpan(), TimeSpan.Parse(item.data.baseData.duration)); + Assert.AreEqual(new TimeSpan(), TimeSpan.Parse(item.data.baseData.domProcessing)); + Assert.AreEqual(new TimeSpan(), TimeSpan.Parse(item.data.baseData.networkConnect)); + Assert.AreEqual(new TimeSpan(), TimeSpan.Parse(item.data.baseData.perfTotal)); + Assert.AreEqual(new TimeSpan(), TimeSpan.Parse(item.data.baseData.receivedResponse)); + Assert.AreEqual(new TimeSpan(), TimeSpan.Parse(item.data.baseData.sentRequest)); + } + } + + + [TestMethod] + public void SanitizeWillTrimAppropriateFields() + { + PageViewPerformanceTelemetry telemetry = new PageViewPerformanceTelemetry(); + telemetry.Name = new string('Z', Property.MaxNameLength + 1); + telemetry.Properties.Add(new string('X', Property.MaxDictionaryNameLength) + 'X', new string('X', Property.MaxValueLength + 1)); + telemetry.Properties.Add(new string('X', Property.MaxDictionaryNameLength) + 'Y', new string('X', Property.MaxValueLength + 1)); + telemetry.Metrics.Add(new string('Y', Property.MaxDictionaryNameLength) + 'X', 42.0); + telemetry.Metrics.Add(new string('Y', Property.MaxDictionaryNameLength) + 'Y', 42.0); + telemetry.Url = new Uri("http://foo.com/" + new string('Y', Property.MaxUrlLength + 1)); + + ((ITelemetry)telemetry).Sanitize(); + + Assert.AreEqual(new string('Z', Property.MaxNameLength), telemetry.Name); + + Assert.AreEqual(2, telemetry.Properties.Count); + string[] keys = telemetry.Properties.Keys.OrderBy(s => s).ToArray(); + string[] values = telemetry.Properties.Values.OrderBy(s => s).ToArray(); + Assert.AreEqual(new string('X', Property.MaxDictionaryNameLength), keys[1]); + Assert.AreEqual(new string('X', Property.MaxValueLength), values[1]); + Assert.AreEqual(new string('X', Property.MaxDictionaryNameLength - 3) + "1", keys[0]); + Assert.AreEqual(new string('X', Property.MaxValueLength), values[0]); + + Assert.AreEqual(2, telemetry.Metrics.Count); + keys = telemetry.Metrics.Keys.OrderBy(s => s).ToArray(); + Assert.AreEqual(new string('Y', Property.MaxDictionaryNameLength), keys[1]); + Assert.AreEqual(new string('Y', Property.MaxDictionaryNameLength - 3) + "1", keys[0]); + + Assert.AreEqual(new Uri("http://foo.com/" + new string('Y', Property.MaxUrlLength - 15)), telemetry.Url); + } + + [TestMethod] + public void SanitizePopulatesNameWithErrorBecauseItIsRequiredByEndpoint() + { + var telemetry = new PageViewPerformanceTelemetry { Name = null }; + + ((ITelemetry)telemetry).Sanitize(); + + Assert.AreEqual("n/a", telemetry.Name); + } + + [TestMethod] + public void PageViewPerformanceTelemetryImplementsISupportSamplingContract() + { + var telemetry = new PageViewPerformanceTelemetry(); + + Assert.IsNotNull(telemetry as ISupportSampling); + } + + [TestMethod] + public void PageViewPerformanceTelemetryHasCorrectValueOfSamplingPercentageAfterSerialization() + { + var telemetry = new PageViewPerformanceTelemetry("my page view"); + ((ISupportSampling)telemetry).SamplingPercentage = 10; + + var item = TelemetryItemTestHelper.SerializeDeserializeTelemetryItem(telemetry); + + Assert.AreEqual(10, item.sampleRate); + } + + [TestMethod] + public void PageViewPerformanceTelemetryDeepCloneCopiesAllProperties() + { + var pageView = new PageViewPerformanceTelemetry("My Page"); + pageView.Url = new Uri("http://temp.org/page1"); + pageView.Duration = TimeSpan.FromSeconds(123); + pageView.Metrics.Add("Metric1", 30); + pageView.Properties.Add("Property1", "Value1"); + pageView.Extension = new MyTestExtension(); + + + PageViewPerformanceTelemetry other = (PageViewPerformanceTelemetry)pageView.DeepClone(); + + CompareLogic deepComparator = new CompareLogic(); + var result = deepComparator.Compare(pageView, other); + Assert.IsTrue(result.AreEqual, result.DifferencesString); + } + + [TestMethod] + public void PageViewPerformanceTelemetryDeepCloneWithNullExtensionDoesNotThrow() + { + var telemetry = new PageViewPerformanceTelemetry(); + // Extension is not set, means it'll be null. + // Validate that cloning with null Extension does not throw. + var other = telemetry.DeepClone(); + } + } +} diff --git a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/PageViewTelemetryTest.cs b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/PageViewTelemetryTest.cs index 4e53611e31..fa671beb86 100644 --- a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/PageViewTelemetryTest.cs +++ b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/PageViewTelemetryTest.cs @@ -96,6 +96,23 @@ public void PageViewTelemetryTelemetryPropertiesFromContextAndItemSerializesToPr Assert.IsTrue(item.data.baseData.properties.ContainsKey("TestProperty")); } + [TestMethod] + public void SerializePopulatesRequiredFieldsOfPageViewTelemetry() + { + using (StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture)) + { + var pvTelemetry = new PageViewTelemetry(); + pvTelemetry.Context.InstrumentationKey = Guid.NewGuid().ToString(); + ((ITelemetry)pvTelemetry).Sanitize(); + var item = TelemetryItemTestHelper.SerializeDeserializeTelemetryItem(pvTelemetry); + + Assert.AreEqual(2, item.data.baseData.ver); + Assert.IsNotNull(item.data.baseData.id); + Assert.IsNotNull(item.time); + Assert.AreEqual(new TimeSpan(), TimeSpan.Parse(item.data.baseData.duration)); + } + } + [TestMethod] public void SanitizeWillTrimAppropriateFields() { @@ -164,12 +181,21 @@ public void PageViewTelemetryDeepCloneCopiesAllProperties() pageView.Duration = TimeSpan.FromSeconds(123); pageView.Metrics.Add("Metric1", 30); pageView.Properties.Add("Property1", "Value1"); - + pageView.Extension = new MyTestExtension(); PageViewTelemetry other = (PageViewTelemetry)pageView.DeepClone(); CompareLogic deepComparator = new CompareLogic(); var result = deepComparator.Compare(pageView, other); Assert.IsTrue(result.AreEqual, result.DifferencesString); } + + [TestMethod] + public void PageViewTelemetryDeepCloneWithNullExtensionDoesNotThrow() + { + var telemetry = new PageViewTelemetry(); + // Extension is not set, means it'll be null. + // Validate that cloning with null Extension does not throw. + var other = telemetry.DeepClone(); + } } } diff --git a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/PerformanceCounterTelemetryTest.cs b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/PerformanceCounterTelemetryTest.cs index 61dbae64de..260cb3cc62 100644 --- a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/PerformanceCounterTelemetryTest.cs +++ b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/PerformanceCounterTelemetryTest.cs @@ -2,6 +2,7 @@ { using System; using Microsoft.ApplicationInsights.Channel; + using Microsoft.ApplicationInsights.Extensibility.Implementation; using Microsoft.VisualStudio.TestTools.UnitTesting; using CompareLogic = KellermanSoftware.CompareNetObjects.CompareLogic; @@ -40,6 +41,7 @@ public void PerformanceCounterTelemetryDeepCloneCopiesAllProperties() PerformanceCounterTelemetry item = new PerformanceCounterTelemetry("someCategory", "someCounter", "an instance", 15.7); item.Timestamp = DateTimeOffset.Now; item.Properties.Add("p1", "p1Val"); + item.Extension = new MyTestExtension(); PerformanceCounterTelemetry other = (PerformanceCounterTelemetry)item.DeepClone(); @@ -48,6 +50,16 @@ public void PerformanceCounterTelemetryDeepCloneCopiesAllProperties() var result = deepComparator.Compare(item, other); Assert.IsTrue(result.AreEqual, result.DifferencesString); } + + [TestMethod] + public void PerformanceCounterTelemetryDeepCloneWithNullExtensionDoesNotThrow() + { + var telemetry = new PerformanceCounterTelemetry(); + // Extension is not set, means it'll be null. + // Validate that cloning with null Extension does not throw. + var other = telemetry.DeepClone(); + } + #pragma warning restore 618 } } diff --git a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/RequestTelemetryTest.cs b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/RequestTelemetryTest.cs index f536615390..40e74dd50b 100644 --- a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/RequestTelemetryTest.cs +++ b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/RequestTelemetryTest.cs @@ -251,6 +251,14 @@ public void RequestTelemetryDeepCloneCopiesAllProperties() Assert.IsTrue(result.AreEqual, result.DifferencesString); } + [TestMethod] + public void RequestTelemetryDeepCloneWithNullExtensionDoesNotThrow() + { + var telemetry = new RequestTelemetry(); + // Extension is not set, means it'll be null. + // Validate that cloning with null Extension does not throw. + var other = telemetry.DeepClone(); + } private RequestTelemetry CreateTestTelemetry() { var request = new RequestTelemetry(); @@ -264,6 +272,7 @@ private RequestTelemetry CreateTestTelemetry() request.Metrics.Add("Metric1", 30); request.Properties.Add("itempropkey", "::1"); request.Context.GlobalProperties.Add("contextpropkey", "contextpropvalue"); + request.Extension = new MyTestExtension(); return request; } } diff --git a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/SessionStateTelemetryTest.cs b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/SessionStateTelemetryTest.cs index 70343d45c8..f15a4910c0 100644 --- a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/SessionStateTelemetryTest.cs +++ b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/SessionStateTelemetryTest.cs @@ -5,6 +5,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using KellermanSoftware.CompareNetObjects; + using Microsoft.ApplicationInsights.Extensibility.Implementation; [TestClass] public class SessionStateTelemetryTest @@ -60,6 +61,7 @@ public void SessionStateTelemetryDeepCloneCopiesAllProperties() { var telemetry = new SessionStateTelemetry(); telemetry.State = SessionState.End; + telemetry.Extension = new MyTestExtension(); var other = telemetry.DeepClone(); CompareLogic deepComparator = new CompareLogic(); @@ -67,6 +69,16 @@ public void SessionStateTelemetryDeepCloneCopiesAllProperties() var result = deepComparator.Compare(telemetry, other); Assert.IsTrue(result.AreEqual, result.DifferencesString); } + + [TestMethod] + public void SessionStateTelemetryDeepCloneWithNullExtensionDoesNotThrow() + { + var telemetry = new SessionStateTelemetry(); + // Extension is not set, means it'll be null. + // Validate that cloning with null Extension does not throw. + var other = telemetry.DeepClone(); + } + #pragma warning restore 618 } } diff --git a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/TelemetryContextTest.cs b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/TelemetryContextTest.cs index 96dd2dd272..5458a5b1bc 100644 --- a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/TelemetryContextTest.cs +++ b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/TelemetryContextTest.cs @@ -252,7 +252,7 @@ private static string CopyAndSerialize(TelemetryContext source) using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - Telemetry.WriteTelemetryContext(new JsonWriter(stringWriter), source); + Telemetry.WriteTelemetryContext(new JsonSerializationWriter(stringWriter), source); return stringWriter.ToString(); } } diff --git a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/TelemetryItemTestHelper.cs b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/TelemetryItemTestHelper.cs index 07b8df65eb..d2b023e5ce 100644 --- a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/TelemetryItemTestHelper.cs +++ b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/TelemetryItemTestHelper.cs @@ -1,14 +1,12 @@ namespace Microsoft.ApplicationInsights.DataContracts { - using System.Globalization; using System.IO; using System.Text; using Microsoft.ApplicationInsights.Channel; using Newtonsoft.Json; using Newtonsoft.Json.Linq; - + using JsonSerializer = Microsoft.ApplicationInsights.Extensibility.Implementation.JsonSerializer; - using JsonWriter = Microsoft.ApplicationInsights.Extensibility.Implementation.JsonWriter; internal static class TelemetryItemTestHelper { diff --git a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/TraceTelemetryTest.cs b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/TraceTelemetryTest.cs index d3239f2996..a69518e0f2 100644 --- a/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/TraceTelemetryTest.cs +++ b/Test/Microsoft.ApplicationInsights.Test/Shared/DataContracts/TraceTelemetryTest.cs @@ -155,6 +155,7 @@ public void TraceTelemetryDeepCloneCopiesAllProperties() trace.SeverityLevel = SeverityLevel.Warning; trace.Sequence = "123456"; trace.Timestamp = DateTimeOffset.Now; + trace.Extension = new MyTestExtension(); var other = trace.DeepClone(); var deepComparator = new CompareLogic(); @@ -163,6 +164,15 @@ public void TraceTelemetryDeepCloneCopiesAllProperties() Assert.IsTrue(result.AreEqual, result.DifferencesString); } + [TestMethod] + public void TraceTelemetryDeepCloneWithNullExtensionDoesNotThrow() + { + var trace = new TraceTelemetry(); + // Extension is not set, means it'll be null. + // Validate that cloning with null Extension does not throw. + var other = trace.DeepClone(); + } + [TestMethod] public void TraceTelemetryPropertiesFromContextAndItemSerializesToPropertiesInJson() { diff --git a/Test/Microsoft.ApplicationInsights.Test/Shared/Extensibility/Implementation/JsonSerializationWriterTests.cs b/Test/Microsoft.ApplicationInsights.Test/Shared/Extensibility/Implementation/JsonSerializationWriterTests.cs new file mode 100644 index 0000000000..d3d0bebf8f --- /dev/null +++ b/Test/Microsoft.ApplicationInsights.Test/Shared/Extensibility/Implementation/JsonSerializationWriterTests.cs @@ -0,0 +1,165 @@ +namespace Microsoft.ApplicationInsights.Extensibility.Implementation +{ + using Microsoft.ApplicationInsights.DataContracts; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Globalization; + using System.IO; + using System.Linq; + using System.Text; + + + /// + /// Tests for + /// + [TestClass] + public class JsonSerializationWriterTests + { + [TestMethod] + public void SerializeComplexObject() + { + var complexExtension = new ComplexExtension(); + var mySubSubExtension1 = new MySubSubExtension() { Field3 = "Value1 for field3", Field4 = 100.00 }; + var mySubSubExtension2 = new MySubSubExtension() { Field3 = "Value2 for field3", Field4 = 200.00 }; + var mySubExtension1 = new MySubExtension() { Field1 = "Value1 for field1", Field2 = 100 , MySubSubExtension = mySubSubExtension1 }; + var mySubExtension2 = new MySubExtension() { Field1 = "Value2 for field1", Field2 = 200, MySubSubExtension = mySubSubExtension2 }; + var listExtension = new List(); + listExtension.Add(mySubExtension1); + listExtension.Add(mySubExtension2); + + var listString = new List(); + listString.Add("Item1"); + listString.Add("Item2"); + listString.Add("Item3"); + + complexExtension.MyBoolField = true; + complexExtension.MyDateTimeOffsetField = DateTimeOffset.Now; + complexExtension.MyDoubleField = 100.10; + complexExtension.MyIntField = 100; + complexExtension.MyStringField = "ValueStringField"; + complexExtension.MyTimeSpanField = TimeSpan.FromSeconds(2); + complexExtension.MySubExtensionField = mySubExtension1; + complexExtension.MyExtensionListField = listExtension; + complexExtension.MyStringListField = listString; + + var dicString = new Dictionary(); + dicString.Add("Key1", "Value1"); + dicString.Add("Key2", "Value2"); + complexExtension.MyStringDictionaryField = dicString; + + var dicDouble = new Dictionary(); + dicDouble.Add("Key1", 1000.000); + dicDouble.Add("Key2", 2000.000); + complexExtension.MyDoubleDictionaryField = dicDouble; + + var stringBuilder = new StringBuilder(); + using (StringWriter stringWriter = new StringWriter(stringBuilder, CultureInfo.InvariantCulture)) + { + var jsonSerializationWriter = new JsonSerializationWriter(stringWriter); + jsonSerializationWriter.WriteStartObject(); + complexExtension.Serialize(jsonSerializationWriter); + jsonSerializationWriter.WriteEndObject(); + } + + string actualJson = stringBuilder.ToString(); + Trace.WriteLine(actualJson); + + JObject obj = JsonConvert.DeserializeObject(actualJson); + + Assert.IsNotNull(actualJson); + Assert.AreEqual("ValueStringField", obj["MyStringField"].ToString()); + Assert.AreEqual(100, int.Parse(obj["MyIntField"].ToString())); + Assert.AreEqual(100.10, double.Parse(obj["MyDoubleField"].ToString())); + Assert.AreEqual(true, bool.Parse(obj["MyBoolField"].ToString())); + Assert.AreEqual(TimeSpan.FromSeconds(2), TimeSpan.Parse(obj["MyTimeSpanField"].ToString())); + //Assert.AreEqual(DateTimeOffset., double.Parse(obj["MyDateTimeOffsetField"].ToString())); + + Assert.AreEqual("Value1 for field1",obj["MySubExtensionField"]["Field1"].ToString()); + Assert.AreEqual(100, int.Parse(obj["MySubExtensionField"]["Field2"].ToString())); + + Assert.AreEqual("Value1 for field3", obj["MySubExtensionField"]["MySubSubExtension"]["Field3"].ToString()); + Assert.AreEqual(100, int.Parse(obj["MySubExtensionField"]["MySubSubExtension"]["Field4"].ToString())); + + Assert.AreEqual("Item1", obj["MyStringListField"][0].ToString()); + Assert.AreEqual("Item2", obj["MyStringListField"][1].ToString()); + Assert.AreEqual("Item3", obj["MyStringListField"][2].ToString()); + + Assert.AreEqual("Value1 for field1", obj["MyExtensionListField"][0]["Field1"].ToString()); + Assert.AreEqual(100, int.Parse(obj["MyExtensionListField"][0]["Field2"].ToString())); + Assert.AreEqual("Value1 for field3", obj["MyExtensionListField"][0]["MySubSubExtension"]["Field3"].ToString()); + Assert.AreEqual(100, int.Parse(obj["MyExtensionListField"][0]["MySubSubExtension"]["Field4"].ToString())); + + Assert.AreEqual("Value2 for field1", obj["MyExtensionListField"][1]["Field1"].ToString()); + Assert.AreEqual(200, int.Parse(obj["MyExtensionListField"][1]["Field2"].ToString())); + Assert.AreEqual("Value2 for field3", obj["MyExtensionListField"][1]["MySubSubExtension"]["Field3"].ToString()); + Assert.AreEqual(200, int.Parse(obj["MyExtensionListField"][1]["MySubSubExtension"]["Field4"].ToString())); + + Assert.AreEqual("Value1", obj["MyStringDictionaryField"]["Key1"].ToString()); + Assert.AreEqual("Value2", obj["MyStringDictionaryField"]["Key2"].ToString()); + + Assert.AreEqual(1000, double.Parse(obj["MyDoubleDictionaryField"]["Key1"].ToString())); + Assert.AreEqual(2000, double.Parse(obj["MyDoubleDictionaryField"]["Key2"].ToString())); + + } + } + + public class ComplexExtension : ISerializableWithWriter + { + public string MyStringField; + public int MyIntField; + public double MyDoubleField; + public bool MyBoolField; + public TimeSpan MyTimeSpanField; + public DateTimeOffset MyDateTimeOffsetField; + public MySubExtension MySubExtensionField; + public IList MyStringListField; + public IList MyExtensionListField; + public IDictionary MyStringDictionaryField; + public IDictionary MyDoubleDictionaryField; + + public void Serialize(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty("MyStringField", MyStringField); + serializationWriter.WriteProperty("MyIntField", MyIntField); + serializationWriter.WriteProperty("MyDoubleField", MyDoubleField); + serializationWriter.WriteProperty("MyBoolField", MyBoolField); + serializationWriter.WriteProperty("MyTimeSpanField", MyTimeSpanField); + serializationWriter.WriteProperty("MyDateTimeOffsetField", MyDateTimeOffsetField); + serializationWriter.WriteProperty("MySubExtensionField", MySubExtensionField); + serializationWriter.WriteProperty("MyStringListField", MyStringListField); + serializationWriter.WriteProperty("MyExtensionListField", MyExtensionListField.ToList()); + serializationWriter.WriteProperty("MyStringDictionaryField", MyStringDictionaryField); + serializationWriter.WriteProperty("MyDoubleDictionaryField", MyDoubleDictionaryField); + } + } + + public class MySubExtension : ISerializableWithWriter + { + public string Field1; + public int Field2; + public ISerializableWithWriter MySubSubExtension; + + public void Serialize(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty("Field1", Field1); + serializationWriter.WriteProperty("Field2", Field2); + serializationWriter.WriteProperty("MySubSubExtension", MySubSubExtension); + } + } + + public class MySubSubExtension : ISerializableWithWriter + { + public string Field3; + public double Field4; + + public void Serialize(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty("Field3", Field3); + serializationWriter.WriteProperty("Field4", Field4); + } + } +} \ No newline at end of file diff --git a/Test/Microsoft.ApplicationInsights.Test/Shared/Extensibility/Implementation/JsonWriterTest.cs b/Test/Microsoft.ApplicationInsights.Test/Shared/Extensibility/Implementation/JsonWriterTest.cs index 0b5910a5b1..895d349a0b 100644 --- a/Test/Microsoft.ApplicationInsights.Test/Shared/Extensibility/Implementation/JsonWriterTest.cs +++ b/Test/Microsoft.ApplicationInsights.Test/Shared/Extensibility/Implementation/JsonWriterTest.cs @@ -10,12 +10,12 @@ using Microsoft.ApplicationInsights.TestFramework; [TestClass] - public class JsonWriterTest + public class JsonSerializationWriterTest { [TestMethod] public void ClassIsInternalAndNotMeantToBeAccessedByCustomers() { - Assert.IsFalse(typeof(JsonWriter).GetTypeInfo().IsPublic); + Assert.IsFalse(typeof(JsonSerializationWriter).GetTypeInfo().IsPublic); } [TestMethod] @@ -23,7 +23,7 @@ public void WriteStartArrayWritesOpeningSquareBracket() { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - new JsonWriter(stringWriter).WriteStartArray(); + new JsonSerializationWriter(stringWriter).WriteStartArray(); Assert.AreEqual("[", stringWriter.ToString()); } } @@ -33,7 +33,7 @@ public void WriteStartObjectWritesOpeningCurlyBrace() { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - new JsonWriter(stringWriter).WriteStartObject(); + new JsonSerializationWriter(stringWriter).WriteStartObject(); Assert.AreEqual("{", stringWriter.ToString()); } } @@ -43,7 +43,7 @@ public void WriteEndArrayWritesClosingSquareBracket() { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - new JsonWriter(stringWriter).WriteEndArray(); + new JsonSerializationWriter(stringWriter).WriteEndArray(); Assert.AreEqual("]", stringWriter.ToString()); } } @@ -53,7 +53,7 @@ public void WriteEndObjectWritesClosingCurlyBrace() { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - new JsonWriter(stringWriter).WriteEndObject(); + new JsonSerializationWriter(stringWriter).WriteEndObject(); Assert.AreEqual("}", stringWriter.ToString()); } } @@ -63,7 +63,7 @@ public void WriteRawValueWritesValueWithoutEscapingValue() { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - new JsonWriter(stringWriter).WriteRawValue(@"Test\Name"); + new JsonSerializationWriter(stringWriter).WriteRawValue(@"Test\Name"); Assert.AreEqual(@"Test\Name", stringWriter.ToString()); } } @@ -77,7 +77,7 @@ public void WritePropertyIntWritesIntValueWithoutQuotationMark() { const string Name = "name"; const int Value = 42; - new JsonWriter(stringWriter).WriteProperty(Name, Value); + new JsonSerializationWriter(stringWriter).WriteProperty(Name, Value); Assert.AreEqual("\"" + Name + "\":" + Value, stringWriter.ToString()); } } @@ -87,7 +87,7 @@ public void WritePropertyIntDoesNothingIfValueIsNullBecauseItAssumesPropertyIsOp { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - new JsonWriter(stringWriter).WriteProperty("name", (int?)null); + new JsonSerializationWriter(stringWriter).WriteProperty("name", (int?)null); Assert.AreEqual(string.Empty, stringWriter.ToString()); } } @@ -103,7 +103,7 @@ public void WritePropertyDoubleWritesDoubleValueWithoutQuotationMark() { const string Name = "name"; const double Value = 42.3; - new JsonWriter(stringWriter).WriteProperty(Name, Value); + new JsonSerializationWriter(stringWriter).WriteProperty(Name, Value); Assert.AreEqual("\"" + Name + "\":" + Value.ToString(CultureInfo.InvariantCulture), stringWriter.ToString()); } } @@ -113,7 +113,7 @@ public void WritePropertyDoubleDoesNothingIfValueIsNullBecauseItAssumesPropertyI { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - new JsonWriter(stringWriter).WriteProperty("name", (double?)null); + new JsonSerializationWriter(stringWriter).WriteProperty("name", (double?)null); Assert.AreEqual(string.Empty, stringWriter.ToString()); } } @@ -129,7 +129,7 @@ public void WritePropertyTimeSpanWritesTimeSpanValueWithQuotationMark() { const string Name = "name"; TimeSpan value = TimeSpan.FromSeconds(123); - new JsonWriter(stringWriter).WriteProperty(Name, value); + new JsonSerializationWriter(stringWriter).WriteProperty(Name, value); Assert.AreEqual("\"" + Name + "\":\"" + value + "\"", stringWriter.ToString()); } } @@ -139,7 +139,7 @@ public void WritePropertyTimeSpanDoesNothingIfValueIsNullBecauseItAssumesPropert { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - new JsonWriter(stringWriter).WriteProperty("name", (TimeSpan?)null); + new JsonSerializationWriter(stringWriter).WriteProperty("name", (TimeSpan?)null); Assert.AreEqual(string.Empty, stringWriter.ToString()); } } @@ -155,7 +155,7 @@ public void WritePropertyStringWritesValueInDoubleQuotes() { const string Name = "name"; const string Value = "value"; - new JsonWriter(stringWriter).WriteProperty(Name, Value); + new JsonSerializationWriter(stringWriter).WriteProperty(Name, Value); Assert.AreEqual("\"" + Name + "\":\"" + Value + "\"", stringWriter.ToString()); } } @@ -165,7 +165,7 @@ public void WritePropertyStringThrowsArgumentNullExceptionForNameInputAsNull() { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - var writer = new JsonWriter(stringWriter); + var writer = new JsonSerializationWriter(stringWriter); AssertEx.Throws(() => writer.WriteProperty(null, "value")); } } @@ -175,7 +175,7 @@ public void WritePropertyStringDoesNothingIfValueIsNullBecauseItAssumesPropertyI { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - new JsonWriter(stringWriter).WriteProperty("name", (string)null); + new JsonSerializationWriter(stringWriter).WriteProperty("name", (string)null); Assert.AreEqual(string.Empty, stringWriter.ToString()); } } @@ -185,7 +185,7 @@ public void WritePropertyStringDoesNothingIfValueIsEmptyBecauseItAssumesProperty { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - new JsonWriter(stringWriter).WriteProperty("name", string.Empty); + new JsonSerializationWriter(stringWriter).WriteProperty("name", string.Empty); Assert.AreEqual(string.Empty, stringWriter.ToString()); } } @@ -201,7 +201,7 @@ public void WritePropertyBooleanWritesValueWithoutQuotationMarks() { const string Name = "name"; const bool Value = true; - new JsonWriter(stringWriter).WriteProperty(Name, Value); + new JsonSerializationWriter(stringWriter).WriteProperty(Name, Value); string expectedValue = Value.ToString().ToLowerInvariant(); Assert.AreEqual("\"" + Name + "\":" + expectedValue, stringWriter.ToString()); } @@ -212,7 +212,7 @@ public void WritePropertyBooleanDoesNothingIfValueIsNullBecauseItAssumesProperty { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - new JsonWriter(stringWriter).WriteProperty("name", (bool?)null); + new JsonSerializationWriter(stringWriter).WriteProperty("name", (bool?)null); Assert.AreEqual(string.Empty, stringWriter.ToString()); } } @@ -224,7 +224,7 @@ public void WritePropertyBooleanWritesFalseBecauseItIsExplicitlySet() { const string Name = "name"; const bool Value = false; - new JsonWriter(stringWriter).WriteProperty(Name, Value); + new JsonSerializationWriter(stringWriter).WriteProperty(Name, Value); string expectedValue = Value.ToString().ToLowerInvariant(); Assert.AreEqual("\"" + Name + "\":" + expectedValue, stringWriter.ToString()); } @@ -241,7 +241,7 @@ public void WritePropertyDateTimeOffsetWritesValueInQuotationMarksAndRoundTripDa { const string Name = "name"; DateTimeOffset value = DateTimeOffset.UtcNow; - new JsonWriter(stringWriter).WriteProperty(Name, value); + new JsonSerializationWriter(stringWriter).WriteProperty(Name, value); string expectedValue = value.ToString("o", CultureInfo.InvariantCulture); Assert.AreEqual("\"" + Name + "\":\"" + expectedValue + "\"", stringWriter.ToString()); } @@ -252,7 +252,7 @@ public void WritePropertyDateTimeOffsetDoesNothingIfValueIsNullBecauseItAssumesP { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - new JsonWriter(stringWriter).WriteProperty("name", (DateTimeOffset?)null); + new JsonSerializationWriter(stringWriter).WriteProperty("name", (DateTimeOffset?)null); Assert.AreEqual(string.Empty, stringWriter.ToString()); } } @@ -266,7 +266,7 @@ public void WritePropertyIDictionaryDoubleWritesPropertyNameFollowedByValuesInCu { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - var writer = new JsonWriter(stringWriter); + var writer = new JsonSerializationWriter(stringWriter); writer.WriteProperty("name", new Dictionary { { "key1", 1 } }); AssertEx.StartsWith("\"name\":{", stringWriter.ToString(), StringComparison.OrdinalIgnoreCase); AssertEx.EndsWith("}", stringWriter.ToString(), StringComparison.OrdinalIgnoreCase); @@ -278,7 +278,7 @@ public void WritePropertyIDictionaryDoubleWritesValuesWithoutDoubleQuotes() { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - var writer = new JsonWriter(stringWriter); + var writer = new JsonSerializationWriter(stringWriter); writer.WriteProperty("name", new Dictionary { { "key1", 1 } }); AssertEx.Contains("\"key1\":1", stringWriter.ToString(), StringComparison.OrdinalIgnoreCase); } @@ -289,7 +289,7 @@ public void WritePropertyIDictionaryDoubleDoesNothingWhenDictionaryIsNullBecause { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - new JsonWriter(stringWriter).WriteProperty("name", (IDictionary)null); + new JsonSerializationWriter(stringWriter).WriteProperty("name", (IDictionary)null); Assert.AreEqual(string.Empty, stringWriter.ToString()); } } @@ -299,7 +299,7 @@ public void WritePropertyIDictionaryDoubleDoesNothingWhenDictionaryIsEmptyBecaus { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - new JsonWriter(stringWriter).WriteProperty("name", new Dictionary()); + new JsonSerializationWriter(stringWriter).WriteProperty("name", new Dictionary()); Assert.AreEqual(string.Empty, stringWriter.ToString()); } } @@ -313,7 +313,7 @@ public void WritePropertyIDictionaryStringStringWritesPropertyNameFollowedByValu { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - var writer = new JsonWriter(stringWriter); + var writer = new JsonSerializationWriter(stringWriter); writer.WriteProperty("name", new Dictionary { { "key1", "1" } }); AssertEx.StartsWith("\"name\":{", stringWriter.ToString(), StringComparison.OrdinalIgnoreCase); AssertEx.EndsWith("}", stringWriter.ToString(), StringComparison.OrdinalIgnoreCase); @@ -325,7 +325,7 @@ public void WritePropertyIDictionaryStringStringWritesValuesWithoutDoubleQuotes( { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - var writer = new JsonWriter(stringWriter); + var writer = new JsonSerializationWriter(stringWriter); writer.WriteProperty("name", new Dictionary { { "key1", "1" } }); AssertEx.Contains("\"key1\":\"1\"", stringWriter.ToString(), StringComparison.OrdinalIgnoreCase); } @@ -336,7 +336,7 @@ public void WritePropertyIDictionaryStringStringDoesNothingWhenDictionaryIsNullB { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - new JsonWriter(stringWriter).WriteProperty("name", (IDictionary)null); + new JsonSerializationWriter(stringWriter).WriteProperty("name", (IDictionary)null); Assert.AreEqual(string.Empty, stringWriter.ToString()); } } @@ -346,7 +346,7 @@ public void WritePropertyIDictionaryStringStringDoesNothingWhenDictionaryIsEmpty { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - new JsonWriter(stringWriter).WriteProperty("name", new Dictionary()); + new JsonSerializationWriter(stringWriter).WriteProperty("name", new Dictionary()); Assert.AreEqual(string.Empty, stringWriter.ToString()); } } @@ -360,7 +360,7 @@ public void WritePropertyNameWritesPropertyNameEnclosedInDoubleQuotationMarksFol { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - new TestableJsonWriter(stringWriter).WritePropertyName("TestProperty"); + new TestableJsonSerializationWriter(stringWriter).WritePropertyName("TestProperty"); Assert.AreEqual("\"TestProperty\":", stringWriter.ToString()); } } @@ -370,9 +370,9 @@ public void WritePropertyNamePrependsPropertyNameWithComaWhenCurrentObjectAlread { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - var jsonWriter = new TestableJsonWriter(stringWriter); - jsonWriter.WritePropertyName("Property1"); - jsonWriter.WritePropertyName("Property2"); + var JsonSerializationWriter = new TestableJsonSerializationWriter(stringWriter); + JsonSerializationWriter.WritePropertyName("Property1"); + JsonSerializationWriter.WritePropertyName("Property2"); AssertEx.Contains(",\"Property2\"", stringWriter.ToString(), StringComparison.OrdinalIgnoreCase); } } @@ -382,10 +382,10 @@ public void WritePropertyNameDoesNotPrependPropertyNameWithComaWhenNewObjectWasS { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - var jsonWriter = new TestableJsonWriter(stringWriter); - jsonWriter.WritePropertyName("Property1"); - jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("Property2"); + var JsonSerializationWriter = new TestableJsonSerializationWriter(stringWriter); + JsonSerializationWriter.WritePropertyName("Property1"); + JsonSerializationWriter.WriteStartObject(); + JsonSerializationWriter.WritePropertyName("Property2"); AssertEx.Contains("{\"Property2\"", stringWriter.ToString(), StringComparison.OrdinalIgnoreCase); } } @@ -395,8 +395,8 @@ public void WritePropertyNameThrowsArgumentExceptionWhenPropertyNameIsEmptyToPre { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - var jsonWriter = new JsonWriter(stringWriter); - AssertEx.Throws(() => jsonWriter.WritePropertyName(string.Empty)); + var JsonSerializationWriter = new JsonSerializationWriter(stringWriter); + AssertEx.Throws(() => JsonSerializationWriter.WritePropertyName(string.Empty)); } } @@ -409,8 +409,8 @@ public void WriteStringEscapesQuotationMark() { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - var jsonWriter = new TestableJsonWriter(stringWriter); - jsonWriter.WriteString("Test\"Value"); + var JsonSerializationWriter = new TestableJsonSerializationWriter(stringWriter); + JsonSerializationWriter.WriteString("Test\"Value"); AssertEx.Contains("Test\\\"Value", stringWriter.ToString(), StringComparison.OrdinalIgnoreCase); } } @@ -420,8 +420,8 @@ public void WriteStringEscapesBackslash() { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - var jsonWriter = new TestableJsonWriter(stringWriter); - jsonWriter.WriteString("Test\\Value"); + var JsonSerializationWriter = new TestableJsonSerializationWriter(stringWriter); + JsonSerializationWriter.WriteString("Test\\Value"); AssertEx.Contains("Test\\\\Value", stringWriter.ToString(), StringComparison.OrdinalIgnoreCase); } } @@ -431,8 +431,8 @@ public void WriteStringEscapesBackspace() { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - var jsonWriter = new TestableJsonWriter(stringWriter); - jsonWriter.WriteString("Test\bValue"); + var JsonSerializationWriter = new TestableJsonSerializationWriter(stringWriter); + JsonSerializationWriter.WriteString("Test\bValue"); AssertEx.Contains("Test\\bValue", stringWriter.ToString(), StringComparison.OrdinalIgnoreCase); } } @@ -442,8 +442,8 @@ public void WriteStringEscapesFormFeed() { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - var jsonWriter = new TestableJsonWriter(stringWriter); - jsonWriter.WriteString("Test\fValue"); + var JsonSerializationWriter = new TestableJsonSerializationWriter(stringWriter); + JsonSerializationWriter.WriteString("Test\fValue"); AssertEx.Contains("Test\\fValue", stringWriter.ToString(), StringComparison.OrdinalIgnoreCase); } } @@ -453,8 +453,8 @@ public void WriteStringEscapesNewline() { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - var jsonWriter = new TestableJsonWriter(stringWriter); - jsonWriter.WriteProperty("name", "Test\nValue"); + var JsonSerializationWriter = new TestableJsonSerializationWriter(stringWriter); + JsonSerializationWriter.WriteProperty("name", "Test\nValue"); AssertEx.Contains("Test\\nValue", stringWriter.ToString(), StringComparison.OrdinalIgnoreCase); } } @@ -464,8 +464,8 @@ public void WriteStringEscapesCarriageReturn() { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - var jsonWriter = new TestableJsonWriter(stringWriter); - jsonWriter.WriteProperty("name", "Test\rValue"); + var JsonSerializationWriter = new TestableJsonSerializationWriter(stringWriter); + JsonSerializationWriter.WriteProperty("name", "Test\rValue"); AssertEx.Contains("Test\\rValue", stringWriter.ToString(), StringComparison.OrdinalIgnoreCase); } } @@ -475,17 +475,17 @@ public void WriteStringEscapesHorizontalTab() { using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture)) { - var jsonWriter = new TestableJsonWriter(stringWriter); - jsonWriter.WriteProperty("name", "Test\tValue"); + var JsonSerializationWriter = new TestableJsonSerializationWriter(stringWriter); + JsonSerializationWriter.WriteProperty("name", "Test\tValue"); AssertEx.Contains("Test\\tValue", stringWriter.ToString(), StringComparison.OrdinalIgnoreCase); } } #endregion - private class TestableJsonWriter : JsonWriter + private class TestableJsonSerializationWriter : JsonSerializationWriter { - public TestableJsonWriter(TextWriter textWriter) + public TestableJsonSerializationWriter(TextWriter textWriter) : base(textWriter) { } diff --git a/Test/Microsoft.ApplicationInsights.Test/Shared/Extensibility/Implementation/MyTestExtension.cs b/Test/Microsoft.ApplicationInsights.Test/Shared/Extensibility/Implementation/MyTestExtension.cs new file mode 100644 index 0000000000..dcf4851579 --- /dev/null +++ b/Test/Microsoft.ApplicationInsights.Test/Shared/Extensibility/Implementation/MyTestExtension.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.ApplicationInsights.Extensibility.Implementation +{ + public class MyTestExtension : IExtension + { + public int myIntField; + public string myStringField; + + public IExtension DeepClone() + { + var other = new MyTestExtension(); + other.myIntField = this.myIntField; + other.myStringField = this.myStringField; + + return other; + } + + public void Serialize(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty("myIntField", myIntField); + serializationWriter.WriteProperty("myStringField", myStringField); + } + } +} diff --git a/Test/Microsoft.ApplicationInsights.Test/Shared/Extensibility/Implementation/RichPayloadEventSourceTest.cs b/Test/Microsoft.ApplicationInsights.Test/Shared/Extensibility/Implementation/RichPayloadEventSourceTest.cs index d6ce49935f..8e695667d6 100644 --- a/Test/Microsoft.ApplicationInsights.Test/Shared/Extensibility/Implementation/RichPayloadEventSourceTest.cs +++ b/Test/Microsoft.ApplicationInsights.Test/Shared/Extensibility/Implementation/RichPayloadEventSourceTest.cs @@ -63,7 +63,7 @@ public void RichPayloadEventSourceEventSentTest() public void RichPayloadEventSourceExceptionSentTest() { var exceptionTelemetry = new ExceptionTelemetry(new SystemException("Test")); - exceptionTelemetry.Data.exceptions[0].parsedStack = new External.StackFrame[] { new External.StackFrame() }; + exceptionTelemetry.Data.Data.exceptions[0].parsedStack = new External.StackFrame[] { new External.StackFrame() }; this.DoTracking( RichPayloadEventSource.Keywords.Exceptions, diff --git a/Test/Microsoft.ApplicationInsights.Test/Shared/Extensibility/TelemetryConfigurationFactoryTest.cs b/Test/Microsoft.ApplicationInsights.Test/Shared/Extensibility/TelemetryConfigurationFactoryTest.cs index 514fd90b4b..8809b943ab 100644 --- a/Test/Microsoft.ApplicationInsights.Test/Shared/Extensibility/TelemetryConfigurationFactoryTest.cs +++ b/Test/Microsoft.ApplicationInsights.Test/Shared/Extensibility/TelemetryConfigurationFactoryTest.cs @@ -328,6 +328,14 @@ public void LoadInstanceConvertsValueToExpectedTypeGivenXmlDefinitionWithNoChild object instance = TestableTelemetryConfigurationFactory.LoadInstance(definition, typeof(int), null, null); Assert.AreEqual(42, instance); } + + [TestMethod] + public void LoadInstanceConvertsValueToExpectedTypeGivenXmlDefinitionWithNoChildElementsParseHexValue() + { + var definition = new XElement("Definition", "0x42"); + object instance = TestableTelemetryConfigurationFactory.LoadInstance(definition, typeof(int), null, null); + Assert.AreEqual(66, instance); + } [TestMethod] public void LoadInstanceTrimsValueOfGivenXmlElementToIgnoreWhitespaceUsersMayAddToConfiguration() diff --git a/Test/Microsoft.ApplicationInsights.Test/Shared/Microsoft.ApplicationInsights.Shared.Tests.projitems b/Test/Microsoft.ApplicationInsights.Test/Shared/Microsoft.ApplicationInsights.Shared.Tests.projitems index 28b848cd0b..a3c10ad4b4 100644 --- a/Test/Microsoft.ApplicationInsights.Test/Shared/Microsoft.ApplicationInsights.Shared.Tests.projitems +++ b/Test/Microsoft.ApplicationInsights.Test/Shared/Microsoft.ApplicationInsights.Shared.Tests.projitems @@ -10,6 +10,9 @@ + + + @@ -113,7 +116,7 @@ - + diff --git a/Test/ServerTelemetryChannel.Test/Shared.Tests/Implementation/TelemetrySerializerTest.cs b/Test/ServerTelemetryChannel.Test/Shared.Tests/Implementation/TelemetrySerializerTest.cs index 58ff199930..7080b04227 100644 --- a/Test/ServerTelemetryChannel.Test/Shared.Tests/Implementation/TelemetrySerializerTest.cs +++ b/Test/ServerTelemetryChannel.Test/Shared.Tests/Implementation/TelemetrySerializerTest.cs @@ -101,7 +101,7 @@ public void EnqueuesTransmissionWithExpectedProperties() Assert.AreEqual(serializer.EndpointAddress, transmission.EndpointAddress); Assert.AreEqual("application/x-json-stream", transmission.ContentType); Assert.AreEqual("gzip", transmission.ContentEncoding); - Assert.AreEqual(string.Empty, Unzip(transmission.Content)); + Assert.AreEqual("{}", Unzip(transmission.Content)); } [TestMethod] diff --git a/Test/TestFramework/Shared/StubTelemetry.cs b/Test/TestFramework/Shared/StubTelemetry.cs index a012bae7fe..c18b02a892 100644 --- a/Test/TestFramework/Shared/StubTelemetry.cs +++ b/Test/TestFramework/Shared/StubTelemetry.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using Microsoft.ApplicationInsights.Channel; using Microsoft.ApplicationInsights.DataContracts; + using Microsoft.ApplicationInsights.Extensibility; using Microsoft.ApplicationInsights.Extensibility.Implementation; internal sealed class StubTelemetry : ITelemetry, ISupportProperties @@ -25,6 +26,7 @@ public StubTelemetry() public TelemetryContext Context { get; set; } public IDictionary Properties { get; set; } + public IExtension Extension { get; set; } public void Serialize(IJsonWriter writer) { @@ -44,5 +46,15 @@ public void SendEvent(object writer) { this.OnSendEvent(writer); } + + public void Serialize(ISerializationWriter serializationWriter) + { + + } + + public void SerializeData(ISerializationWriter serializationWriter) + { + + } } } diff --git a/docs/ServerTelemetryChannel error handling.md b/docs/ServerTelemetryChannel error handling.md index c3d7763c82..50351824f6 100644 --- a/docs/ServerTelemetryChannel error handling.md +++ b/docs/ServerTelemetryChannel error handling.md @@ -50,8 +50,8 @@ Notes: * This policy handles failures with status codes 408, 500, 503 * "Set timer to restore capacity using Retry-After or exponential backoff" means that * We check that Retry-After header is present. In the header we expect to get TimeSpan. Timer is set to restore capacity after this interval. (Note that with current backend implementation Retry-After is never returned for 408, 500, 503). - * If Retry-After header is not present we check how many consecutive errors occured so far and use exponential backoff algorythm to set a timer to restore capacity. Exponential backoff algorythm description: http://en.wikipedia.org/wiki/Exponential_backoff -* We do not update number of consecutive errors if it was recently updated because we have mupliple sender that most likely to fail at the same time for intermittent issues. + * If Retry-After header is not present we check how many y consecutive errors occurred so far and use exponential backoff algorythm to set a timer to restore capacity. Exponential backoff algorythm description: http://en.wikipedia.org/wiki/Exponential_backoff +* We do not update number of consecutive errors if it was recently updated because we have multiple sender that most likely to fail at the same time for intermittent issues. ![Img](./images/ErrorHandlingPolicy.PNG) @@ -72,7 +72,7 @@ Notes: ### [NetworkAvailabilityTransmissionPolicy](https://github.com/Microsoft/ApplicationInsights-dotnet/blob/master/src/TelemetryChannels/ServerTelemetryChannel/Shared/Implementation/NetworkAvailabilityTransmissionPolicy.cs) -This policy subscribes to the [network change event](https://msdn.microsoft.com/en-us/library/system.net.networkinformation.networkchange.networkaddresschanged%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396). When network becomes unavailable sender and buffer capacity are set to 0. Note that consecutive errors count that affects exponental backoff logic is not changed. +This policy subscribes to the [network change event](https://msdn.microsoft.com/en-us/library/system.net.networkinformation.networkchange.networkaddresschanged%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396). When network becomes unavailable sender and buffer capacity are set to 0. Note that consecutive errors count that affects exponential backoff logic is not changed. ### [ApplicationLifecycleTransmissionPolicy](https://github.com/Microsoft/ApplicationInsights-dotnet/blob/master/src/TelemetryChannels/ServerTelemetryChannel/Shared/Implementation/ApplicationLifecycleTransmissionPolicy.cs) diff --git a/src/Microsoft.ApplicationInsights/Channel/ITelemetry.cs b/src/Microsoft.ApplicationInsights/Channel/ITelemetry.cs index d4043ad045..a33e48e4e4 100644 --- a/src/Microsoft.ApplicationInsights/Channel/ITelemetry.cs +++ b/src/Microsoft.ApplicationInsights/Channel/ITelemetry.cs @@ -2,6 +2,7 @@ { using System; using Microsoft.ApplicationInsights.DataContracts; + using Microsoft.ApplicationInsights.Extensibility; /// /// The base telemetry type for application insights. @@ -18,6 +19,12 @@ public interface ITelemetry /// TelemetryContext Context { get; } + /// + /// Gets or sets gets the extension used to extend this telemetry instance using new strongly + /// typed object. + /// + IExtension Extension { get; set; } + /// /// Gets or sets the value that defines absolute order of the telemetry item. /// @@ -43,5 +50,10 @@ public interface ITelemetry /// /// The cloned object. ITelemetry DeepClone(); + + /// + /// Writes serialization info about the data class of the implementing type using the given + /// + void SerializeData(ISerializationWriter serializationWriter); } } diff --git a/src/Microsoft.ApplicationInsights/DataContracts/AvailabilityTelemetry.cs b/src/Microsoft.ApplicationInsights/DataContracts/AvailabilityTelemetry.cs index 8c0409cfd0..188a0caac1 100644 --- a/src/Microsoft.ApplicationInsights/DataContracts/AvailabilityTelemetry.cs +++ b/src/Microsoft.ApplicationInsights/DataContracts/AvailabilityTelemetry.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Globalization; using Microsoft.ApplicationInsights.Channel; + using Microsoft.ApplicationInsights.Extensibility; using Microsoft.ApplicationInsights.Extensibility.Implementation; using Microsoft.ApplicationInsights.Extensibility.Implementation.External; @@ -19,6 +20,7 @@ public sealed class AvailabilityTelemetry : ITelemetry, ISupportProperties, ISup internal readonly string BaseType = typeof(AvailabilityData).Name; internal readonly AvailabilityData Data; private readonly TelemetryContext context; + private IExtension extension; /// /// Initializes a new instance of the class with empty properties. @@ -55,6 +57,7 @@ private AvailabilityTelemetry(AvailabilityTelemetry source) this.context = source.context.DeepClone(this.Data.properties); this.Sequence = source.Sequence; this.Timestamp = source.Timestamp; + this.extension = source.extension?.DeepClone(); } /// @@ -131,6 +134,15 @@ public TelemetryContext Context get { return this.context; } } + /// + /// Gets or sets gets the extension used to extend this telemetry instance using new strong typed object. + /// + public IExtension Extension + { + get { return this.extension; } + set { this.extension = value; } + } + /// /// Gets a dictionary of application-defined property names and values providing additional information about this availability test run. /// Learn more @@ -166,6 +178,12 @@ public ITelemetry DeepClone() return new AvailabilityTelemetry(this); } + /// + public void SerializeData(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty(this.Data); + } + /// /// Sanitizes the properties based on constraints. /// diff --git a/src/Microsoft.ApplicationInsights/DataContracts/DependencyTelemetry.cs b/src/Microsoft.ApplicationInsights/DataContracts/DependencyTelemetry.cs index 55a7e0d86f..1f60edeab4 100644 --- a/src/Microsoft.ApplicationInsights/DataContracts/DependencyTelemetry.cs +++ b/src/Microsoft.ApplicationInsights/DataContracts/DependencyTelemetry.cs @@ -4,6 +4,7 @@ namespace Microsoft.ApplicationInsights.DataContracts using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; + using System.Globalization; using Microsoft.ApplicationInsights.Channel; using Microsoft.ApplicationInsights.Extensibility; using Microsoft.ApplicationInsights.Extensibility.Implementation; @@ -23,6 +24,7 @@ public sealed class DependencyTelemetry : OperationTelemetry, ITelemetry, ISuppo internal readonly RemoteDependencyData InternalData; private readonly TelemetryContext context; + private IExtension extension; private IDictionary operationDetails; private double? samplingPercentage; @@ -98,6 +100,7 @@ private DependencyTelemetry(DependencyTelemetry source) this.Timestamp = source.Timestamp; this.samplingPercentage = source.samplingPercentage; this.successFieldSet = source.successFieldSet; + this.extension = source.extension?.DeepClone(); // Only clone the details if the source has had details initialized if (source.operationDetails != null) @@ -124,6 +127,15 @@ public override TelemetryContext Context get { return this.context; } } + /// + /// Gets or sets gets the extension used to extend this telemetry instance using new strongly typed object. + /// + public override IExtension Extension + { + get { return this.extension; } + set { this.extension = value; } + } + /// /// Gets or sets Dependency ID. /// @@ -329,6 +341,12 @@ public void SetOperationDetail(string key, object detail) this.OperationDetails[key] = detail; } + /// + public override void SerializeData(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty(this.InternalData); + } + /// /// Sanitizes the properties based on constraints. /// diff --git a/src/Microsoft.ApplicationInsights/DataContracts/EventTelemetry.cs b/src/Microsoft.ApplicationInsights/DataContracts/EventTelemetry.cs index 172ce1fe19..2eea99a979 100644 --- a/src/Microsoft.ApplicationInsights/DataContracts/EventTelemetry.cs +++ b/src/Microsoft.ApplicationInsights/DataContracts/EventTelemetry.cs @@ -2,8 +2,10 @@ { using System; using System.Collections.Generic; + using System.Globalization; using System.Threading; using Microsoft.ApplicationInsights.Channel; + using Microsoft.ApplicationInsights.Extensibility; using Microsoft.ApplicationInsights.Extensibility.Implementation; using Microsoft.ApplicationInsights.Extensibility.Implementation.External; @@ -18,6 +20,7 @@ public sealed class EventTelemetry : ITelemetry, ISupportProperties, ISupportSam internal readonly string BaseType = typeof(EventData).Name; internal readonly EventData Data; private readonly TelemetryContext context; + private IExtension extension; private double? samplingPercentage; @@ -45,6 +48,7 @@ private EventTelemetry(EventTelemetry source) this.Sequence = source.Sequence; this.Timestamp = source.Timestamp; this.samplingPercentage = source.samplingPercentage; + this.extension = source.extension?.DeepClone(); } /// @@ -65,6 +69,15 @@ public TelemetryContext Context get { return this.context; } } + /// + /// Gets or sets gets the extension used to extend this telemetry instance using new strong typed object. + /// + public IExtension Extension + { + get { return this.extension; } + set { this.extension = value; } + } + /// /// Gets or sets the name of the event. /// @@ -121,5 +134,11 @@ void ITelemetry.Sanitize() this.Properties.SanitizeProperties(); this.Metrics.SanitizeMeasurements(); } + + /// + public void SerializeData(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty(this.Data); + } } } diff --git a/src/Microsoft.ApplicationInsights/DataContracts/ExceptionDetailsInfo.cs b/src/Microsoft.ApplicationInsights/DataContracts/ExceptionDetailsInfo.cs new file mode 100644 index 0000000000..059508196f --- /dev/null +++ b/src/Microsoft.ApplicationInsights/DataContracts/ExceptionDetailsInfo.cs @@ -0,0 +1,64 @@ +namespace Microsoft.ApplicationInsights.DataContracts +{ + using System.Collections.Generic; + using System.Linq; + using Microsoft.ApplicationInsights.Extensibility.Implementation.External; + + /// + /// Wrapper class for that lets user gets/sets TypeName and Message. + /// + public sealed class ExceptionDetailsInfo + { + internal readonly ExceptionDetails InternalExceptionDetails = null; + + /// + /// Constructs the instance of . + /// + /// Exception id. + /// Parent exception's id. + /// Type name for the exception. + /// Exception message. + /// Indicates that this exception has full stack information. + /// Exception's stack trace. + /// Exception's stack. + public ExceptionDetailsInfo(int id, int outerId, string typeName, string message, bool hasFullStack, + string stack, IEnumerable parsedStack) + { + this.InternalExceptionDetails = new ExceptionDetails() + { + id = id, + outerId = outerId, + typeName = typeName, + message = message, + hasFullStack = hasFullStack, + stack = stack, + parsedStack = parsedStack.Select(ps => ps.Data).ToList() + }; + } + + internal ExceptionDetailsInfo(ExceptionDetails exceptionDetails) + { + this.InternalExceptionDetails = exceptionDetails; + } + + /// + /// Gets or sets type name of the underlying that this object represents. + /// + public string TypeName + { + get => this.InternalExceptionDetails.typeName; + set => this.InternalExceptionDetails.typeName = value; + } + + /// + /// Gets or sets message name of the underlying that this object represents. + /// + public string Message + { + get => this.InternalExceptionDetails.message; + set => this.InternalExceptionDetails.message = value; + } + + internal ExceptionDetails ExceptionDetails => this.InternalExceptionDetails; + } +} \ No newline at end of file diff --git a/src/Microsoft.ApplicationInsights/DataContracts/ExceptionInfo.cs b/src/Microsoft.ApplicationInsights/DataContracts/ExceptionInfo.cs new file mode 100644 index 0000000000..869a84a56d --- /dev/null +++ b/src/Microsoft.ApplicationInsights/DataContracts/ExceptionInfo.cs @@ -0,0 +1,85 @@ +namespace Microsoft.ApplicationInsights.DataContracts +{ + using System.Collections.Concurrent; + using System.Collections.Generic; + using System.Linq; + using Extensibility.Implementation; + using Extensibility.Implementation.External; + + /// + /// Wrapper class for that lets user provide exception data without having the actual Exception object. + /// + internal sealed class ExceptionInfo + { + private readonly ExceptionData data; + + /// + /// Constructs the instance of + /// + public ExceptionInfo(IEnumerable exceptionDetailsInfoList, SeverityLevel? severityLevel, string problemId, + IDictionary properties, IDictionary measurements) + { + this.data = new ExceptionData + { + exceptions = exceptionDetailsInfoList.Select(edi => edi.ExceptionDetails).ToList(), + severityLevel = severityLevel.TranslateSeverityLevel(), + problemId = problemId, + properties = new ConcurrentDictionary(properties), + measurements = new ConcurrentDictionary(measurements) + }; + } + + internal ExceptionInfo(ExceptionData data) + { + this.data = data; + } + + /// + /// Gets a list of to modify as needed. + /// + public IReadOnlyList ExceptionDetailsInfoList => this.data.exceptions.Select(ed => new ExceptionDetailsInfo(ed)).ToList().AsReadOnly(); + + /// + /// Gets or sets Exception severity level. + /// + public SeverityLevel? SeverityLevel + { + get => this.data.severityLevel.TranslateSeverityLevel(); + set => this.data.severityLevel = value.TranslateSeverityLevel(); + } + + /// + /// Gets or sets problem id. + /// + public string ProblemId + { + get => this.data.problemId; + set => this.data.problemId = value; + } + + /// + /// Gets or sets properties collection. + /// + public IDictionary Properties + { + get => this.data.properties; + set => this.data.properties = value; + } + + /// + /// Gets or sets measurements collection. + /// + public IDictionary Measurements + { + get => this.data.measurements; + set => this.data.measurements = value; + } + + internal ExceptionData Data => this.data; + + internal ExceptionInfo DeepClone() + { + return new ExceptionInfo(this.data.DeepClone()); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.ApplicationInsights/DataContracts/ExceptionTelemetry.cs b/src/Microsoft.ApplicationInsights/DataContracts/ExceptionTelemetry.cs index 75fafb93ec..ae762674aa 100644 --- a/src/Microsoft.ApplicationInsights/DataContracts/ExceptionTelemetry.cs +++ b/src/Microsoft.ApplicationInsights/DataContracts/ExceptionTelemetry.cs @@ -3,7 +3,9 @@ using System; using System.Collections.Generic; using System.Globalization; + using System.Linq; using Microsoft.ApplicationInsights.Channel; + using Microsoft.ApplicationInsights.Extensibility; using Microsoft.ApplicationInsights.Extensibility.Implementation; using Microsoft.ApplicationInsights.Extensibility.Implementation.External; @@ -15,12 +17,14 @@ public sealed class ExceptionTelemetry : ITelemetry, ISupportProperties, ISuppor { internal const string TelemetryName = "Exception"; internal readonly string BaseType = typeof(ExceptionData).Name; - internal readonly ExceptionData Data; + internal ExceptionInfo Data = null; - private readonly TelemetryContext context; + private readonly bool isCreatedFromExceptionInfo = false; + + private TelemetryContext context; + private IExtension extension; private Exception exception; private string message; - private double? samplingPercentage; /// @@ -28,8 +32,8 @@ public sealed class ExceptionTelemetry : ITelemetry, ISupportProperties, ISuppor /// public ExceptionTelemetry() { - this.Data = new ExceptionData(); - this.context = new TelemetryContext(this.Data.properties); + this.Data = new ExceptionInfo(new ExceptionData()); + this.context = new TelemetryContext(this.Data.Properties); } /// @@ -47,18 +51,47 @@ public ExceptionTelemetry(Exception exception) this.Exception = exception; } + /// + /// Initializes a new instance of the class. + /// + /// Exception info. + /// Severity level. + /// Problem id. + /// Properties. + /// Measurements. + public ExceptionTelemetry(IEnumerable exceptionDetailsInfoList, SeverityLevel? severityLevel, string problemId, + IDictionary properties, IDictionary measurements) + { + this.isCreatedFromExceptionInfo = true; + + ExceptionInfo exceptionInfo = new ExceptionInfo(exceptionDetailsInfoList, severityLevel, problemId, properties, measurements); + + this.Data = exceptionInfo; + this.context = new TelemetryContext(this.Data.Properties); + + this.UpdateData(exceptionInfo); + } + /// /// Initializes a new instance of the class by cloning an existing instance. /// /// Source instance of to clone from. private ExceptionTelemetry(ExceptionTelemetry source) { + this.isCreatedFromExceptionInfo = source.isCreatedFromExceptionInfo; + this.Data = source.Data.DeepClone(); - this.context = source.context.DeepClone(this.Data.properties); + this.context = source.context.DeepClone(this.Data.Properties); this.Sequence = source.Sequence; this.Timestamp = source.Timestamp; this.samplingPercentage = source.samplingPercentage; - this.Exception = source.Exception; + + if (!this.isCreatedFromExceptionInfo) + { + this.exception = source.Exception; + } + + this.extension = source.extension?.DeepClone(); } /// @@ -79,6 +112,15 @@ public TelemetryContext Context get { return this.context; } } + /// + /// Gets or sets gets the extension used to extend this telemetry instance using new strong typed object. + /// + public IExtension Extension + { + get { return this.extension; } + set { this.extension = value; } + } + /// /// Gets or sets the problemId. /// @@ -86,12 +128,12 @@ public string ProblemId { get { - return this.Data.problemId; + return this.Data.ProblemId; } set { - this.Data.problemId = value; + this.Data.ProblemId = value; } } @@ -125,13 +167,22 @@ public Exception Exception { get { - return this.exception; + return this.isCreatedFromExceptionInfo + ? throw new InvalidOperationException( + "The property is unavailable on an instance created from an ExceptionInfo object") + : this.exception; } set { + if (this.isCreatedFromExceptionInfo) + { + throw new InvalidOperationException( + "The property is unavailable on an instance created from an ExceptionInfo object"); + } + this.exception = value; - this.UpdateExceptions(value); + this.UpdateData(value); } } @@ -142,20 +193,29 @@ public string Message { get { - return this.message; + return this.isCreatedFromExceptionInfo + ? throw new InvalidOperationException( + "The property is unavailable on an instance created from an ExceptionInfo object") + : this.message; } set { + if (this.isCreatedFromExceptionInfo) + { + throw new InvalidOperationException( + "The property is unavailable on an instance created from an ExceptionInfo object"); + } + this.message = value; - if (this.Data.exceptions != null && this.Data.exceptions.Count > 0) + if (this.Data.ExceptionDetailsInfoList != null && this.Data.ExceptionDetailsInfoList.Count > 0) { - this.Data.exceptions[0].message = value; + this.Data.ExceptionDetailsInfoList[0].Message = value; } else { - this.UpdateExceptions(this.Exception); + this.UpdateData(this.Exception); } } } @@ -166,16 +226,22 @@ public string Message /// public IDictionary Metrics { - get { return this.Data.measurements; } + get { return this.Data.Measurements; } } + /// + /// Gets the list of . User can modify the contents of individual object, but + /// not the list itself. + /// + public IReadOnlyList ExceptionDetailsInfoList => this.Data.ExceptionDetailsInfoList; + /// /// Gets a dictionary of application-defined property names and values providing additional information about this exception. /// Learn more /// public IDictionary Properties { - get { return this.Data.properties; } + get { return this.Data.Properties; } } /// @@ -183,8 +249,8 @@ public IDictionary Properties /// public SeverityLevel? SeverityLevel { - get { return this.Data.severityLevel.TranslateSeverityLevel(); } - set { this.Data.severityLevel = value.TranslateSeverityLevel(); } + get => this.Data.SeverityLevel; + set => this.Data.SeverityLevel = value; } /// @@ -199,7 +265,7 @@ public SeverityLevel? SeverityLevel internal IList Exceptions { - get { return this.Data.exceptions; } + get { return this.Data.Data.exceptions; } } /// @@ -211,25 +277,29 @@ public ITelemetry DeepClone() return new ExceptionTelemetry(this); } + /// + public void SerializeData(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty(this.Data.Data); + } + /// /// Set parsedStack from an array of StackFrame objects. /// public void SetParsedStack(System.Diagnostics.StackFrame[] frames) { - List orderedStackTrace = new List(); - if (this.Exceptions != null && this.Exceptions.Count > 0) { if (frames != null && frames.Length > 0) { int stackLength = 0; - this.Exceptions[0].parsedStack = new List(); + this.Exceptions[0].parsedStack = new List(); this.Exceptions[0].hasFullStack = true; for (int level = 0; level < frames.Length; level++) { - StackFrame sf = ExceptionConverter.GetStackFrame(frames[level], level); + var sf = ExceptionConverter.GetStackFrame(frames[level], level); stackLength += ExceptionConverter.GetStackFrameLength(sf); @@ -286,8 +356,13 @@ private void ConvertExceptionTree(Exception exception, ExceptionDetails parentEx } } - private void UpdateExceptions(Exception exception) + private void UpdateData(Exception exception) { + if (this.isCreatedFromExceptionInfo) + { + throw new InvalidOperationException("Operation is not supported given the state of the object."); + } + // collect the set of exceptions detail info from the passed in exception List exceptions = new List(); this.ConvertExceptionTree(exception, null, exceptions); @@ -297,21 +372,36 @@ private void UpdateExceptions(Exception exception) { // TODO: when we localize these messages, we should consider not using InvariantCulture // create our "message" exception. - InnerExceptionCountExceededException countExceededException = new InnerExceptionCountExceededException( - string.Format( - CultureInfo.InvariantCulture, - "The number of inner exceptions was {0} which is larger than {1}, the maximum number allowed during transmission. All but the first {1} have been dropped.", - exceptions.Count, - Constants.MaxExceptionCountToSave)); + InnerExceptionCountExceededException countExceededException = + new InnerExceptionCountExceededException( + string.Format( + CultureInfo.InvariantCulture, + "The number of inner exceptions was {0} which is larger than {1}, the maximum number allowed during transmission. All but the first {1} have been dropped.", + exceptions.Count, + Constants.MaxExceptionCountToSave)); // remove all but the first N exceptions - exceptions.RemoveRange(Constants.MaxExceptionCountToSave, exceptions.Count - Constants.MaxExceptionCountToSave); + exceptions.RemoveRange(Constants.MaxExceptionCountToSave, + exceptions.Count - Constants.MaxExceptionCountToSave); // we'll add our new exception and parent it to the root exception (first one in the list) exceptions.Add(ExceptionConverter.ConvertToExceptionDetails(countExceededException, exceptions[0])); } - this.Data.exceptions = exceptions; + this.Data = new ExceptionInfo(exceptions.Select(ex => new ExceptionDetailsInfo(ex)), this.SeverityLevel, + this.ProblemId, this.Properties, this.Metrics); + this.context = new TelemetryContext(this.Data.Properties); + } + + private void UpdateData(ExceptionInfo exceptionInfo) + { + if (!this.isCreatedFromExceptionInfo) + { + throw new InvalidOperationException("Operation is not supported given the state of the object."); + } + + this.Data = exceptionInfo ?? throw new ArgumentNullException(nameof(exceptionInfo)); + this.context = new TelemetryContext(this.Data.Properties); } } } diff --git a/src/Microsoft.ApplicationInsights/DataContracts/MetricTelemetry.cs b/src/Microsoft.ApplicationInsights/DataContracts/MetricTelemetry.cs index a936256af0..d62d5331a9 100644 --- a/src/Microsoft.ApplicationInsights/DataContracts/MetricTelemetry.cs +++ b/src/Microsoft.ApplicationInsights/DataContracts/MetricTelemetry.cs @@ -3,7 +3,9 @@ using System; using System.Collections.Generic; using System.ComponentModel; + using System.Globalization; using Microsoft.ApplicationInsights.Channel; + using Microsoft.ApplicationInsights.Extensibility; using Microsoft.ApplicationInsights.Extensibility.Implementation; using Microsoft.ApplicationInsights.Extensibility.Implementation.External; @@ -15,10 +17,10 @@ public sealed class MetricTelemetry : ITelemetry, ISupportProperties { internal const string TelemetryName = "Metric"; - internal readonly string BaseType = typeof(MetricData).Name; - + internal readonly string BaseType = typeof(MetricData).Name; internal readonly MetricData Data; internal readonly DataPoint Metric; + private IExtension extension; /// /// Initializes a new instance of the class with empty @@ -131,6 +133,7 @@ private MetricTelemetry(MetricTelemetry source) this.Context = source.Context.DeepClone(this.Data.properties); this.Sequence = source.Sequence; this.Timestamp = source.Timestamp; + this.extension = source.extension?.DeepClone(); } /// @@ -148,6 +151,15 @@ private MetricTelemetry(MetricTelemetry source) /// public TelemetryContext Context { get; } + /// + /// Gets or sets gets the extension used to extend this telemetry instance using new strong typed object. + /// + public IExtension Extension + { + get { return this.extension; } + set { this.extension = value; } + } + /// /// Gets or sets the name of the metric. /// @@ -239,6 +251,12 @@ public ITelemetry DeepClone() return new MetricTelemetry(this); } + /// + public void SerializeData(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty(this.Data); + } + /// /// Sanitizes the properties based on constraints. /// diff --git a/src/Microsoft.ApplicationInsights/DataContracts/PageViewPerformanceTelemetry.cs b/src/Microsoft.ApplicationInsights/DataContracts/PageViewPerformanceTelemetry.cs new file mode 100644 index 0000000000..ee0f9995b7 --- /dev/null +++ b/src/Microsoft.ApplicationInsights/DataContracts/PageViewPerformanceTelemetry.cs @@ -0,0 +1,234 @@ +namespace Microsoft.ApplicationInsights.DataContracts +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using Microsoft.ApplicationInsights.Channel; + using Microsoft.ApplicationInsights.Extensibility; + using Microsoft.ApplicationInsights.Extensibility.Implementation; + using Microsoft.ApplicationInsights.Extensibility.Implementation.External; + + /// + /// Telemetry type used to track page load performance. + /// + public sealed class PageViewPerformanceTelemetry : ITelemetry, ISupportProperties, ISupportSampling + { + internal const string TelemetryName = "PageViewPerformance"; + + internal const string BaseType = "PageViewPerformanceData"; + + internal readonly PageViewPerfData Data; + private IExtension extension; + private double? samplingPercentage; + + /// + /// Initializes a new instance of the class. + /// + public PageViewPerformanceTelemetry() + { + this.Data = new PageViewPerfData(); + this.Context = new TelemetryContext(this.Data.properties); + } + + /// + /// Initializes a new instance of the class with the + /// specified . + /// + /// The is null or empty string. + public PageViewPerformanceTelemetry(string pageName) : this() + { + this.Name = pageName; + } + + /// + /// Initializes a new instance of the class by cloning an existing instance. + /// + /// Source instance of to clone from. + private PageViewPerformanceTelemetry(PageViewPerformanceTelemetry source) + { + this.Data = source.Data.DeepClone(); + this.Context = source.Context.DeepClone(this.Data.properties); + this.extension = source.extension?.DeepClone(); + } + + /// + /// Gets or sets date and time when event was recorded. + /// + public DateTimeOffset Timestamp { get; set; } + + /// + /// Gets or sets the value that defines absolute order of the telemetry item. + /// + public string Sequence { get; set; } + + /// + /// Gets the context associated with the current telemetry item. + /// + public TelemetryContext Context { get; private set; } + + /// + /// Gets or sets gets the extension used to extend this telemetry instance using new strong typed object. + /// + public IExtension Extension + { + get { return this.extension; } + set { this.extension = value; } + } + + /// + /// Gets or sets page view ID. + /// + public string Id + { + get { return this.Data.id; } + set { this.Data.id = value; } + } + + /// + /// Gets or sets the name of the page. + /// + public string Name + { + get { return this.Data.name; } + set { this.Data.name = value; } + } + + /// + /// Gets or sets the page view Uri. + /// + public Uri Url + { + get + { + if (this.Data.url.IsNullOrWhiteSpace()) + { + return null; + } + + return new Uri(this.Data.url, UriKind.RelativeOrAbsolute); + } + + set + { + if (value == null) + { + this.Data.url = null; + } + else + { + this.Data.url = value.ToString(); + } + } + } + + /// + /// Gets or sets the page view duration. + /// + public TimeSpan Duration + { + get { return Utils.ValidateDuration(this.Data.duration); } + set { this.Data.duration = value.ToString(); } + } + + /// + /// Gets or sets the page DOM processing time. + /// + public TimeSpan DomProcessing + { + get { return Utils.ValidateDuration(this.Data.domProcessing); } + set { this.Data.domProcessing = value.ToString(); } + } + + /// + /// Gets or sets the page loading total time. + /// + public TimeSpan PerfTotal + { + get { return Utils.ValidateDuration(this.Data.perfTotal); } + set { this.Data.perfTotal = value.ToString(); } + } + + /// + /// Gets or sets the page load network time. + /// + public TimeSpan NetworkConnect + { + get { return Utils.ValidateDuration(this.Data.networkConnect); } + set { this.Data.networkConnect = value.ToString(); } + } + + /// + /// Gets or sets the page load send request time. + /// + public TimeSpan SentRequest + { + get { return Utils.ValidateDuration(this.Data.sentRequest); } + set { this.Data.sentRequest = value.ToString(); } + } + + /// + /// Gets or sets the page load recieve response duration. + /// + public TimeSpan ReceivedResponse + { + get { return Utils.ValidateDuration(this.Data.receivedResponse); } + set { this.Data.receivedResponse = value.ToString(); } + } + + /// + /// Gets a dictionary of custom defined metrics. + /// Learn more + /// + public IDictionary Metrics + { + get { return this.Data.measurements; } + } + + /// + /// Gets a dictionary of application-defined property names and values providing additional information about this page view. + /// Learn more + /// + public IDictionary Properties + { + get { return this.Data.properties; } + } + + /// + /// Gets or sets data sampling percentage (between 0 and 100). + /// Should be 100/n where n is an integer. Learn more + /// + double? ISupportSampling.SamplingPercentage + { + get { return this.samplingPercentage; } + set { this.samplingPercentage = value; } + } + + /// + /// Deeply clones a object. + /// + /// A cloned instance. + public ITelemetry DeepClone() + { + return new PageViewPerformanceTelemetry(this); + } + + /// + /// Sanitizes the properties based on constraints. + /// + void ITelemetry.Sanitize() + { + this.Name = this.Name.SanitizeName(); + this.Name = Utils.PopulateRequiredStringValue(this.Name, "name", typeof(PageViewTelemetry).FullName); + this.Properties.SanitizeProperties(); + this.Metrics.SanitizeMeasurements(); + this.Url = this.Url.SanitizeUri(); + this.Id.SanitizeName(); + } + + /// + public void SerializeData(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty(this.Data); + } + } +} diff --git a/src/Microsoft.ApplicationInsights/DataContracts/PageViewTelemetry.cs b/src/Microsoft.ApplicationInsights/DataContracts/PageViewTelemetry.cs index a5442dd0a1..fd7fc7c654 100644 --- a/src/Microsoft.ApplicationInsights/DataContracts/PageViewTelemetry.cs +++ b/src/Microsoft.ApplicationInsights/DataContracts/PageViewTelemetry.cs @@ -5,6 +5,7 @@ using System.Globalization; using System.Threading; using Microsoft.ApplicationInsights.Channel; + using Microsoft.ApplicationInsights.Extensibility; using Microsoft.ApplicationInsights.Extensibility.Implementation; using Microsoft.ApplicationInsights.Extensibility.Implementation.External; @@ -21,10 +22,10 @@ public sealed class PageViewTelemetry : ITelemetry, ISupportProperties, ISupport { internal const string TelemetryName = "PageView"; - internal readonly string BaseType = typeof(PageViewData).Name; - + internal readonly string BaseType = typeof(PageViewData).Name; internal readonly PageViewData Data; private readonly TelemetryContext context; + private IExtension extension; private double? samplingPercentage; @@ -55,6 +56,7 @@ private PageViewTelemetry(PageViewTelemetry source) { this.Data = source.Data.DeepClone(); this.context = source.context.DeepClone(this.Data.properties); + this.extension = source.extension?.DeepClone(); } /// @@ -75,6 +77,15 @@ public TelemetryContext Context get { return this.context; } } + /// + /// Gets or sets gets the extension used to extend this telemetry instance using new strong typed object. + /// + public IExtension Extension + { + get { return this.extension; } + set { this.extension = value; } + } + /// /// Gets or sets page view ID. /// @@ -167,6 +178,12 @@ public ITelemetry DeepClone() return new PageViewTelemetry(this); } + /// + public void SerializeData(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty(this.Data); + } + /// /// Sanitizes the properties based on constraints. /// diff --git a/src/Microsoft.ApplicationInsights/DataContracts/PerformanceCounterTelemetry.cs b/src/Microsoft.ApplicationInsights/DataContracts/PerformanceCounterTelemetry.cs index 7c89011484..62854cf869 100644 --- a/src/Microsoft.ApplicationInsights/DataContracts/PerformanceCounterTelemetry.cs +++ b/src/Microsoft.ApplicationInsights/DataContracts/PerformanceCounterTelemetry.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using Channel; + using Microsoft.ApplicationInsights.Extensibility; /// /// The class that represents information about performance counters. @@ -11,8 +12,7 @@ [Obsolete("Use MetricTelemetry instead.")] public sealed class PerformanceCounterTelemetry : ITelemetry, ISupportProperties { - internal readonly MetricTelemetry Data; - + internal readonly MetricTelemetry Data; private string categoryName = string.Empty; private string counterName = string.Empty; @@ -94,6 +94,15 @@ public TelemetryContext Context } } + /// + /// Gets or sets gets the extension used to extend this telemetry instance using new strong typed object. + /// + public IExtension Extension + { + get { return this.Data.Extension; } + set { this.Data.Extension = value; } + } + /// /// Gets or sets the counter value. /// @@ -183,6 +192,12 @@ public ITelemetry DeepClone() return new PerformanceCounterTelemetry(this); } + /// + public void SerializeData(ISerializationWriter serializationWriter) + { + this.Data.SerializeData(serializationWriter); + } + /// /// Sanitizes the properties based on constraints. /// diff --git a/src/Microsoft.ApplicationInsights/DataContracts/RequestTelemetry.cs b/src/Microsoft.ApplicationInsights/DataContracts/RequestTelemetry.cs index 12f65d7267..76192ac44d 100644 --- a/src/Microsoft.ApplicationInsights/DataContracts/RequestTelemetry.cs +++ b/src/Microsoft.ApplicationInsights/DataContracts/RequestTelemetry.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Globalization; using Microsoft.ApplicationInsights.Channel; + using Microsoft.ApplicationInsights.Extensibility; using Microsoft.ApplicationInsights.Extensibility.Implementation; using Microsoft.ApplicationInsights.Extensibility.Implementation.External; @@ -24,7 +25,7 @@ public sealed class RequestTelemetry : OperationTelemetry, ITelemetry, ISupportP internal readonly RequestData Data; private readonly TelemetryContext context; private bool successFieldSet; - + private IExtension extension; private double? samplingPercentage; /// @@ -62,6 +63,7 @@ private RequestTelemetry(RequestTelemetry source) this.Sequence = source.Sequence; this.Timestamp = source.Timestamp; this.successFieldSet = source.successFieldSet; + this.extension = source.extension?.DeepClone(); } /// @@ -82,6 +84,15 @@ public override TelemetryContext Context get { return this.context; } } + /// + /// Gets or sets gets the extension used to extend this telemetry instance using new strong typed object. + /// + public override IExtension Extension + { + get { return this.extension; } + set { this.extension = value; } + } + /// /// Gets or sets Request ID. /// @@ -224,6 +235,12 @@ public override ITelemetry DeepClone() return new RequestTelemetry(this); } + /// + public override void SerializeData(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty(this.Data); + } + /// /// Sanitizes the properties based on constraints. /// diff --git a/src/Microsoft.ApplicationInsights/DataContracts/SessionStateTelemetry.cs b/src/Microsoft.ApplicationInsights/DataContracts/SessionStateTelemetry.cs index 6079268db8..ff23946a4d 100644 --- a/src/Microsoft.ApplicationInsights/DataContracts/SessionStateTelemetry.cs +++ b/src/Microsoft.ApplicationInsights/DataContracts/SessionStateTelemetry.cs @@ -2,6 +2,7 @@ { using System; using Microsoft.ApplicationInsights.Channel; + using Microsoft.ApplicationInsights.Extensibility; /// /// Telemetry type used to track user sessions. @@ -67,6 +68,15 @@ public TelemetryContext Context get { return this.Data.Context; } } + /// + /// Gets or sets gets the extension used to extend this telemetry instance using new strong typed object. + /// + public IExtension Extension + { + get { return this.Data.Extension; } + set { this.Data.Extension = value; } + } + /// /// Gets or sets the value that defines absolute order of the telemetry item. /// @@ -129,5 +139,11 @@ void ITelemetry.Sanitize() { ((ITelemetry)this.Data).Sanitize(); } + + /// + public void SerializeData(ISerializationWriter serializationWriter) + { + this.Data.SerializeData(serializationWriter); + } } -} +} \ No newline at end of file diff --git a/src/Microsoft.ApplicationInsights/DataContracts/StackFrame.cs b/src/Microsoft.ApplicationInsights/DataContracts/StackFrame.cs new file mode 100644 index 0000000000..b2755741dc --- /dev/null +++ b/src/Microsoft.ApplicationInsights/DataContracts/StackFrame.cs @@ -0,0 +1,27 @@ +namespace Microsoft.ApplicationInsights.DataContracts +{ + using System; + + /// + /// Wrapper class for for API exposure. + /// + public sealed class StackFrame + { + /// + /// Constructs an instance. + /// + public StackFrame(string assembly, string fileName, int level, int line, string method) + { + this.Data = new Extensibility.Implementation.External.StackFrame() + { + assembly = assembly, + fileName = fileName, + level = level, + line = line, + method = method + }; + } + + internal Extensibility.Implementation.External.StackFrame Data { get; private set; } = null; + } +} \ No newline at end of file diff --git a/src/Microsoft.ApplicationInsights/DataContracts/TelemetryContext.cs b/src/Microsoft.ApplicationInsights/DataContracts/TelemetryContext.cs index bfc40703a4..2d342eb7f7 100644 --- a/src/Microsoft.ApplicationInsights/DataContracts/TelemetryContext.cs +++ b/src/Microsoft.ApplicationInsights/DataContracts/TelemetryContext.cs @@ -139,6 +139,7 @@ public LocationContext Location /// Gets a dictionary of application-defined property values. /// Learn more /// + [Obsolete("Use GlobalProperties to set global level properties. For properties at item level, use ISupportProperties.Properties.")] public IDictionary Properties { get { return this.properties; } @@ -149,7 +150,7 @@ public IDictionary Properties /// Future SDK versions could serialize this separately from the item level properties. /// Learn more /// - internal IDictionary GlobalProperties + public IDictionary GlobalProperties { get { return this.globalProperties; } } diff --git a/src/Microsoft.ApplicationInsights/DataContracts/TraceTelemetry.cs b/src/Microsoft.ApplicationInsights/DataContracts/TraceTelemetry.cs index 054c833699..4282760fa1 100644 --- a/src/Microsoft.ApplicationInsights/DataContracts/TraceTelemetry.cs +++ b/src/Microsoft.ApplicationInsights/DataContracts/TraceTelemetry.cs @@ -2,7 +2,9 @@ { using System; using System.Collections.Generic; + using System.Globalization; using Microsoft.ApplicationInsights.Channel; + using Microsoft.ApplicationInsights.Extensibility; using Microsoft.ApplicationInsights.Extensibility.Implementation; using Microsoft.ApplicationInsights.Extensibility.Implementation.External; @@ -18,6 +20,7 @@ public sealed class TraceTelemetry : ITelemetry, ISupportProperties, ISupportSam internal readonly string BaseType = typeof(MessageData).Name; internal readonly MessageData Data; private readonly TelemetryContext context; + private IExtension extension; private double? samplingPercentage; @@ -57,6 +60,7 @@ private TraceTelemetry(TraceTelemetry source) this.Sequence = source.Sequence; this.Timestamp = source.Timestamp; this.samplingPercentage = source.samplingPercentage; + this.extension = source.extension?.DeepClone(); } /// @@ -77,6 +81,15 @@ public TelemetryContext Context get { return this.context; } } + /// + /// Gets or sets gets the extension used to extend this telemetry instance using new strong typed object. + /// + public IExtension Extension + { + get { return this.extension; } + set { this.extension = value; } + } + /// /// Gets or sets the message text. For example, the text that would normally be written to a log file line. /// @@ -123,6 +136,12 @@ public ITelemetry DeepClone() return new TraceTelemetry(this); } + /// + public void SerializeData(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty(this.Data); + } + /// /// Sanitizes the properties based on constraints. /// diff --git a/src/Microsoft.ApplicationInsights/Extensibility/IExtension.cs b/src/Microsoft.ApplicationInsights/Extensibility/IExtension.cs new file mode 100644 index 0000000000..8681097cfe --- /dev/null +++ b/src/Microsoft.ApplicationInsights/Extensibility/IExtension.cs @@ -0,0 +1,13 @@ +namespace Microsoft.ApplicationInsights.Extensibility +{ + /// + /// Interface for defining strongly typed extensions to telemetry types. + /// + public interface IExtension : ISerializableWithWriter + { + /// + /// Deep clones the members of the class. + /// + IExtension DeepClone(); + } +} diff --git a/src/Microsoft.ApplicationInsights/Extensibility/ISerializableWithWriter.cs b/src/Microsoft.ApplicationInsights/Extensibility/ISerializableWithWriter.cs new file mode 100644 index 0000000000..a1e4ab5064 --- /dev/null +++ b/src/Microsoft.ApplicationInsights/Extensibility/ISerializableWithWriter.cs @@ -0,0 +1,13 @@ +namespace Microsoft.ApplicationInsights.Extensibility +{ + /// + /// Interface for defining objects which can be serialized with a given + /// + public interface ISerializableWithWriter + { + /// + /// Writes serialization info about the class using the given + /// + void Serialize(ISerializationWriter serializationWriter); + } +} diff --git a/src/Microsoft.ApplicationInsights/Extensibility/ISerializationWriter.cs b/src/Microsoft.ApplicationInsights/Extensibility/ISerializationWriter.cs new file mode 100644 index 0000000000..83f5591e05 --- /dev/null +++ b/src/Microsoft.ApplicationInsights/Extensibility/ISerializationWriter.cs @@ -0,0 +1,86 @@ +namespace Microsoft.ApplicationInsights.Extensibility +{ + using System; + using System.Collections.Generic; + + /// + /// The interface for defining writers capable of serializing data into various formats. + /// + public interface ISerializationWriter + { + /// + /// Writes name and value for a string field + /// + void WriteProperty(string name, string value); + + /// + /// Writes name and value for a double field + /// + void WriteProperty(string name, double? value); + + /// + /// Writes name and value for a int field + /// + void WriteProperty(string name, int? value); + + /// + /// Writes name and value for a boolean field + /// + void WriteProperty(string name, bool? value); + + /// + /// Writes name and value for a TimeSpan field + /// + void WriteProperty(string name, TimeSpan? value); + + /// + /// Writes name and value for a DateTimeOffset field + /// + void WriteProperty(string name, DateTimeOffset? value); + + /// + /// Writes name and value for a ISerializableWithWriter field + /// + void WriteProperty(string name, ISerializableWithWriter value); + + /// + /// Writes value ISerializableWithWriter field + /// + void WriteProperty(ISerializableWithWriter value); + + /// + /// Writes name and values for a IList field of strings + /// + void WriteProperty(string name, IList items); + + /// + /// Writes name and values for a IList field of objects implementing ISerializableWithWriter + /// + void WriteProperty(string name, IList items); + + /// + /// Writes name and value for a IDictionary field with string,string as key,value + /// + void WriteProperty(string name, IDictionary items); + + /// + /// Writes name and value for a IDictionary field with string,string as key,value + /// + void WriteProperty(string name, IDictionary items); + + /// + /// Marks beginning of a complex object. + /// + void WriteStartObject(string name); + + /// + /// Marks beginning of a complex object. + /// + void WriteStartObject(); + + /// + /// Marks ending of a complex object. + /// + void WriteEndObject(); + } +} \ No newline at end of file diff --git a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/AvailabilityDataISerializableWithWriter.cs b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/AvailabilityDataISerializableWithWriter.cs new file mode 100644 index 0000000000..5bde401a42 --- /dev/null +++ b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/AvailabilityDataISerializableWithWriter.cs @@ -0,0 +1,25 @@ +namespace Microsoft.ApplicationInsights.Extensibility.Implementation.External +{ + using System.Diagnostics; + using Microsoft.ApplicationInsights; + using Microsoft.ApplicationInsights.DataContracts; + + /// + /// Partial class to implement ISerializableWithWriter + /// + internal partial class AvailabilityData : ISerializableWithWriter + { + public void Serialize(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty("ver", this.ver); + serializationWriter.WriteProperty("id", this.id); + serializationWriter.WriteProperty("name", this.name); + serializationWriter.WriteProperty("duration", Utils.ValidateDuration(this.duration)); + serializationWriter.WriteProperty("success", this.success); + serializationWriter.WriteProperty("runLocation", this.runLocation); + serializationWriter.WriteProperty("message", this.message); + serializationWriter.WriteProperty("properties", this.properties); + serializationWriter.WriteProperty("measurements", this.measurements); + } + } +} diff --git a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/DataPointIExtension.cs b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/DataPointIExtension.cs new file mode 100644 index 0000000000..bd654095a7 --- /dev/null +++ b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/DataPointIExtension.cs @@ -0,0 +1,22 @@ +namespace Microsoft.ApplicationInsights.Extensibility.Implementation.External +{ + using Microsoft.ApplicationInsights.DataContracts; + + /// + /// Partial class to implement ISerializableWithWriter + /// + internal partial class DataPoint : ISerializableWithWriter + { + public void Serialize(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty("ns", this.ns); + serializationWriter.WriteProperty("name", this.name); + serializationWriter.WriteProperty("kind", this.kind.ToString()); + serializationWriter.WriteProperty("value", this.value); + serializationWriter.WriteProperty("count", this.count.HasValue ? this.count : 1); + serializationWriter.WriteProperty("min", this.min); + serializationWriter.WriteProperty("max", this.max); + serializationWriter.WriteProperty("stdDev", this.stdDev); + } + } +} diff --git a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/EventDataISerializableWithWriter.cs b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/EventDataISerializableWithWriter.cs new file mode 100644 index 0000000000..1820667ae9 --- /dev/null +++ b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/EventDataISerializableWithWriter.cs @@ -0,0 +1,21 @@ +namespace Microsoft.ApplicationInsights.Extensibility.Implementation.External +{ + using System.Diagnostics; + using Microsoft.ApplicationInsights; + using Microsoft.ApplicationInsights.DataContracts; + + /// + /// Partial class to implement ISerializableWithWriter + /// + internal partial class EventData : ISerializableWithWriter + { + public void Serialize(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty("ver", this.ver); + serializationWriter.WriteProperty("name", this.name); + + serializationWriter.WriteProperty("properties", this.properties); + serializationWriter.WriteProperty("measurements", this.measurements); + } + } +} diff --git a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/ExceptionDataISerializableWithWriter.cs b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/ExceptionDataISerializableWithWriter.cs new file mode 100644 index 0000000000..c385f58564 --- /dev/null +++ b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/ExceptionDataISerializableWithWriter.cs @@ -0,0 +1,25 @@ +namespace Microsoft.ApplicationInsights.Extensibility.Implementation.External +{ + using System; + using System.Diagnostics; + using System.Linq; + using Microsoft.ApplicationInsights; + using Microsoft.ApplicationInsights.DataContracts; + + /// + /// Partial class to implement ISerializableWithWriter + /// + internal partial class ExceptionData : ISerializableWithWriter + { + public void Serialize(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty("ver", this.ver); + serializationWriter.WriteProperty("problemId", this.problemId); + serializationWriter.WriteProperty("exceptions", this.exceptions.ToList()); + serializationWriter.WriteProperty("severityLevel", this.severityLevel.TranslateSeverityLevel().HasValue ? this.severityLevel.TranslateSeverityLevel().Value.ToString() : null); + + serializationWriter.WriteProperty("properties", this.properties); + serializationWriter.WriteProperty("measurements", this.measurements); + } + } +} diff --git a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/ExceptionDetailsISerializableWithWriter.cs b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/ExceptionDetailsISerializableWithWriter.cs new file mode 100644 index 0000000000..5e2e918d33 --- /dev/null +++ b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/ExceptionDetailsISerializableWithWriter.cs @@ -0,0 +1,22 @@ +namespace Microsoft.ApplicationInsights.Extensibility.Implementation.External +{ + using System; + using System.Linq; + + /// + /// Partial class to implement ISerializableWithWriter. + /// + internal partial class ExceptionDetails : ISerializableWithWriter + { + public void Serialize(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty("id", this.id); + serializationWriter.WriteProperty("outerId", this.outerId); + serializationWriter.WriteProperty("typeName", this.typeName); + serializationWriter.WriteProperty("message", this.message); + serializationWriter.WriteProperty("hasFullStack", this.hasFullStack); + serializationWriter.WriteProperty("stack", this.stack); + serializationWriter.WriteProperty("parsedStack", this.parsedStack.ToList()); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/MessageDataIExtension.cs b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/MessageDataIExtension.cs new file mode 100644 index 0000000000..592fe1e6af --- /dev/null +++ b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/MessageDataIExtension.cs @@ -0,0 +1,22 @@ +namespace Microsoft.ApplicationInsights.Extensibility.Implementation.External +{ + using System; + using System.Diagnostics; + using Microsoft.ApplicationInsights; + using Microsoft.ApplicationInsights.DataContracts; + + /// + /// Partial class to implement ISerializableWithWriter + /// + internal partial class MessageData : ISerializableWithWriter + { + public void Serialize(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty("ver", this.ver); + serializationWriter.WriteProperty("message", this.message); + serializationWriter.WriteProperty("severityLevel", this.severityLevel.HasValue ? this.severityLevel.Value.ToString() : null); + serializationWriter.WriteProperty("properties", this.properties); + serializationWriter.WriteProperty("measurements", this.measurements); + } + } +} diff --git a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/MetricDataISerializableWithWriter.cs b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/MetricDataISerializableWithWriter.cs new file mode 100644 index 0000000000..89eb5e72a7 --- /dev/null +++ b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/MetricDataISerializableWithWriter.cs @@ -0,0 +1,20 @@ +namespace Microsoft.ApplicationInsights.Extensibility.Implementation.External +{ + using System.Diagnostics; + using System.Linq; + using Microsoft.ApplicationInsights; + using Microsoft.ApplicationInsights.DataContracts; + + /// + /// Partial class to implement ISerializableWithWriter + /// + internal partial class MetricData : ISerializableWithWriter + { + public void Serialize(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty("ver", this.ver); + serializationWriter.WriteProperty("metrics", this.metrics.ToList()); + serializationWriter.WriteProperty("properties", this.properties); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/PageViewDataIExtension.cs b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/PageViewDataIExtension.cs new file mode 100644 index 0000000000..f1eadb1a53 --- /dev/null +++ b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/PageViewDataIExtension.cs @@ -0,0 +1,20 @@ +namespace Microsoft.ApplicationInsights.Extensibility.Implementation.External +{ + using Microsoft.ApplicationInsights.DataContracts; + + /// + /// Partial class to implement ISerializableWithWriter + /// + internal partial class PageViewData : ISerializableWithWriter + { + public new void Serialize(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty("ver", this.ver); + serializationWriter.WriteProperty("name", this.name); + serializationWriter.WriteProperty("url", this.url); + serializationWriter.WriteProperty("duration", Utils.ValidateDuration(this.duration)); + serializationWriter.WriteProperty("properties", this.properties); + serializationWriter.WriteProperty("measurements", this.measurements); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/PageViewPerfData.cs b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/PageViewPerfData.cs index b9a2259138..14fbec9eb0 100644 --- a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/PageViewPerfData.cs +++ b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/PageViewPerfData.cs @@ -1,14 +1,34 @@ namespace Microsoft.ApplicationInsights.Extensibility.Implementation.External { -#if NET45 - // .Net 4.5 has a custom implementation of RichPayloadEventSource -#else /// /// Partial class to add the EventData attribute and any additional customizations to the generated type. /// +#if NET45 + // .Net 4.5 has a custom implementation of RichPayloadEventSource +#else [System.Diagnostics.Tracing.EventData(Name = "PartB_PageViewPerfData")] +#endif internal partial class PageViewPerfData { + public new PageViewPerfData DeepClone() + { + var other = new PageViewPerfData(); + this.ApplyProperties(other); + return other; + } + + protected override void ApplyProperties(EventData other) + { + base.ApplyProperties(other); + PageViewPerfData otherPageViewPerf = other as PageViewPerfData; + if (otherPageViewPerf != null) + { + otherPageViewPerf.domProcessing = this.domProcessing; + otherPageViewPerf.perfTotal = this.perfTotal; + otherPageViewPerf.networkConnect = this.networkConnect; + otherPageViewPerf.sentRequest = this.sentRequest; + otherPageViewPerf.receivedResponse = this.receivedResponse; + } + } } -#endif } \ No newline at end of file diff --git a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/PageViewPerfDataIExtension.cs b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/PageViewPerfDataIExtension.cs new file mode 100644 index 0000000000..7417ff207c --- /dev/null +++ b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/PageViewPerfDataIExtension.cs @@ -0,0 +1,23 @@ +namespace Microsoft.ApplicationInsights.Extensibility.Implementation.External +{ + /// + /// Partial class to implement ISerializableWithWriter + /// + internal partial class PageViewPerfData : ISerializableWithWriter + { + public new void Serialize(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty("ver", this.ver); + serializationWriter.WriteProperty("name", this.name); + serializationWriter.WriteProperty("url", this.url); + serializationWriter.WriteProperty("duration", Utils.ValidateDuration(this.duration)); + serializationWriter.WriteProperty("domProcessing", Utils.ValidateDuration(this.domProcessing)); + serializationWriter.WriteProperty("perfTotal", Utils.ValidateDuration(this.perfTotal)); + serializationWriter.WriteProperty("networkConnect", Utils.ValidateDuration(this.networkConnect)); + serializationWriter.WriteProperty("sentRequest", Utils.ValidateDuration(this.sentRequest)); + serializationWriter.WriteProperty("receivedResponse", Utils.ValidateDuration(this.receivedResponse)); + serializationWriter.WriteProperty("properties", this.properties); + serializationWriter.WriteProperty("measurements", this.measurements); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/RemoteDependencyDataISerializableWithWriter.cs b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/RemoteDependencyDataISerializableWithWriter.cs new file mode 100644 index 0000000000..87b4c96f3b --- /dev/null +++ b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/RemoteDependencyDataISerializableWithWriter.cs @@ -0,0 +1,27 @@ +namespace Microsoft.ApplicationInsights.Extensibility.Implementation.External +{ + using System.Diagnostics; + using Microsoft.ApplicationInsights; + using Microsoft.ApplicationInsights.DataContracts; + + /// + /// Partial class to implement ISerializableWithWriter + /// + internal partial class RemoteDependencyData : ISerializableWithWriter + { + public void Serialize(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty("ver", this.ver); + serializationWriter.WriteProperty("name", this.name); + serializationWriter.WriteProperty("id", this.id); + serializationWriter.WriteProperty("data", this.data); + serializationWriter.WriteProperty("duration", Utils.ValidateDuration(this.duration)); + serializationWriter.WriteProperty("resultCode", this.resultCode); + serializationWriter.WriteProperty("success", this.success); + serializationWriter.WriteProperty("type", this.type); + serializationWriter.WriteProperty("target", this.target); + serializationWriter.WriteProperty("properties", this.properties); + serializationWriter.WriteProperty("measurements", this.measurements); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/RequestDataISerializableWithWriter.cs b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/RequestDataISerializableWithWriter.cs new file mode 100644 index 0000000000..1da9c3a024 --- /dev/null +++ b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/RequestDataISerializableWithWriter.cs @@ -0,0 +1,26 @@ +namespace Microsoft.ApplicationInsights.Extensibility.Implementation.External +{ + using System.Diagnostics; + using Microsoft.ApplicationInsights; + using Microsoft.ApplicationInsights.DataContracts; + + /// + /// Partial class to implement ISerializableWithWriter + /// + internal partial class RequestData : ISerializableWithWriter + { + public void Serialize(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty("ver", this.ver); + serializationWriter.WriteProperty("id", this.id); + serializationWriter.WriteProperty("source", this.source); + serializationWriter.WriteProperty("name", this.name); + serializationWriter.WriteProperty("duration", Utils.ValidateDuration(this.duration)); + serializationWriter.WriteProperty("success", this.success); + serializationWriter.WriteProperty("responseCode", this.responseCode); + serializationWriter.WriteProperty("url", this.url); + serializationWriter.WriteProperty("properties", this.properties); + serializationWriter.WriteProperty("measurements", this.measurements); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/StackFrameISerializableWithWriter.cs b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/StackFrameISerializableWithWriter.cs new file mode 100644 index 0000000000..4e00b4e532 --- /dev/null +++ b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/StackFrameISerializableWithWriter.cs @@ -0,0 +1,19 @@ +namespace Microsoft.ApplicationInsights.Extensibility.Implementation.External +{ + using System; + + /// + /// Partial class to impelement ISerializableWithWriter + /// + internal partial class StackFrame : ISerializableWithWriter + { + public void Serialize(ISerializationWriter serializationWriter) + { + serializationWriter.WriteProperty("level", this.level); + serializationWriter.WriteProperty("method", this.method); + serializationWriter.WriteProperty("assembly", this.assembly); + serializationWriter.WriteProperty("fileName", this.fileName); + serializationWriter.WriteProperty("line", this.line); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/JsonWriter.cs b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/JsonSerializationWriter.cs similarity index 62% rename from src/Microsoft.ApplicationInsights/Extensibility/Implementation/JsonWriter.cs rename to src/Microsoft.ApplicationInsights/Extensibility/Implementation/JsonSerializationWriter.cs index ef9f353dd0..59e6326685 100644 --- a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/JsonWriter.cs +++ b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/JsonSerializationWriter.cs @@ -1,81 +1,67 @@ namespace Microsoft.ApplicationInsights.Extensibility.Implementation -{ +{ using System; using System.Collections.Generic; using System.Globalization; using System.IO; - using Microsoft.ApplicationInsights.DataContracts; + using Microsoft.ApplicationInsights.Extensibility; - internal class JsonWriter : IJsonWriter + internal class JsonSerializationWriter : ISerializationWriter { - private readonly EmptyObjectDetector emptyObjectDetector; private readonly TextWriter textWriter; private bool currentObjectHasProperties; - internal JsonWriter(TextWriter textWriter) + public JsonSerializationWriter(TextWriter textWriter) { - this.emptyObjectDetector = new EmptyObjectDetector(); - this.textWriter = textWriter; - } - - public void WriteStartArray() - { - this.textWriter.Write('['); + this.textWriter = textWriter; } + /// public void WriteStartObject() - { + { this.textWriter.Write('{'); this.currentObjectHasProperties = false; } - public void WriteEndArray() - { - this.textWriter.Write(']'); - } - - public void WriteEndObject() + /// + public void WriteStartObject(string name) { - this.textWriter.Write('}'); - } - - public void WriteComma() - { - this.textWriter.Write(','); - } - - public void WriteRawValue(object value) - { - this.textWriter.Write(string.Format(CultureInfo.InvariantCulture, "{0}", value)); - } + this.WritePropertyName(name); + this.textWriter.Write('{'); + this.currentObjectHasProperties = false; + } + /// public void WriteProperty(string name, string value) { if (!string.IsNullOrEmpty(value)) - { + { this.WritePropertyName(name); this.WriteString(value); } } - public void WriteProperty(string name, bool? value) + /// + public void WriteProperty(string name, int? value) { if (value.HasValue) { this.WritePropertyName(name); - this.textWriter.Write(value.Value ? "true" : "false"); + this.textWriter.Write(value.Value.ToString(CultureInfo.InvariantCulture)); } } - public void WriteProperty(string name, int? value) + /// + public void WriteProperty(string name, bool? value) { if (value.HasValue) { this.WritePropertyName(name); - this.textWriter.Write(value.Value.ToString(CultureInfo.InvariantCulture)); + this.textWriter.Write(value.Value ? "true" : "false"); } } + /// public void WriteProperty(string name, double? value) { if (value.HasValue) @@ -85,6 +71,7 @@ public void WriteProperty(string name, double? value) } } + /// public void WriteProperty(string name, TimeSpan? value) { if (value.HasValue) @@ -93,6 +80,7 @@ public void WriteProperty(string name, TimeSpan? value) } } + /// public void WriteProperty(string name, DateTimeOffset? value) { if (value.HasValue) @@ -101,6 +89,77 @@ public void WriteProperty(string name, DateTimeOffset? value) } } + /// + public void WriteProperty(string name, IList items) + { + bool commaNeeded = false; + if (items != null && items.Count > 0) + { + this.WritePropertyName(name); + + this.WriteStartArray(); + + foreach (var item in items) + { + if (commaNeeded) + { + this.WriteComma(); + } + + this.WriteString(item); + commaNeeded = true; + } + + this.WriteEndArray(); + } + } + + /// + public void WriteProperty(string name, IList items) + { + bool commaNeeded = false; + if (items != null && items.Count > 0) + { + this.WritePropertyName(name); + this.WriteStartArray(); + foreach (var item in items) + { + if (commaNeeded) + { + this.WriteComma(); + } + + this.WriteStartObject(); + item.Serialize(this); + commaNeeded = true; + this.WriteEndObject(); + } + + this.WriteEndArray(); + } + } + + /// + public void WriteProperty(string name, ISerializableWithWriter value) + { + if (value != null) + { + this.WriteStartObject(name); + value.Serialize(this); + this.WriteEndObject(); + } + } + + /// + public void WriteProperty(ISerializableWithWriter value) + { + if (value != null) + { + value.Serialize(this); + } + } + + /// public void WriteProperty(string name, IDictionary values) { if (values != null && values.Count > 0) @@ -116,6 +175,7 @@ public void WriteProperty(string name, IDictionary values) } } + /// public void WriteProperty(string name, IDictionary values) { if (values != null && values.Count > 0) @@ -131,14 +191,13 @@ public void WriteProperty(string name, IDictionary values) } } - /// - /// Writes the specified property name enclosed in double quotation marks followed by a colon. - /// - /// - /// When this method is called multiple times, the second call after - /// and all subsequent calls will write a coma before the name. - /// - public void WritePropertyName(string name) + /// + public void WriteEndObject() + { + this.textWriter.Write('}'); + } + + internal void WritePropertyName(string name) { if (name == null) { @@ -162,8 +221,28 @@ public void WritePropertyName(string name) this.WriteString(name); this.textWriter.Write(':'); } - - protected void WriteString(string value) + + internal void WriteStartArray() + { + this.textWriter.Write('['); + } + + internal void WriteEndArray() + { + this.textWriter.Write(']'); + } + + internal void WriteComma() + { + this.textWriter.Write(','); + } + + internal void WriteRawValue(object value) + { + this.textWriter.Write(string.Format(CultureInfo.InvariantCulture, "{0}", value)); + } + + internal void WriteString(string value) { this.textWriter.Write('"'); @@ -209,106 +288,5 @@ protected void WriteString(string value) this.textWriter.Write('"'); } - - private sealed class EmptyObjectDetector : IJsonWriter - { - public bool IsEmpty { get; set; } - - public void WriteStartArray() - { - } - - public void WriteStartObject() - { - } - - public void WriteEndArray() - { - } - - public void WriteEndObject() - { - } - - public void WriteComma() - { - } - - public void WriteProperty(string name, string value) - { - if (!string.IsNullOrEmpty(value)) - { - this.IsEmpty = false; - } - } - - public void WriteProperty(string name, bool? value) - { - if (value.HasValue) - { - this.IsEmpty = false; - } - } - - public void WriteProperty(string name, int? value) - { - if (value.HasValue) - { - this.IsEmpty = false; - } - } - - public void WriteProperty(string name, double? value) - { - if (value.HasValue) - { - this.IsEmpty = false; - } - } - - public void WriteProperty(string name, TimeSpan? value) - { - if (value.HasValue) - { - this.IsEmpty = false; - } - } - - public void WriteProperty(string name, DateTimeOffset? value) - { - if (value.HasValue) - { - this.IsEmpty = false; - } - } - - public void WriteProperty(string name, IDictionary value) - { - if (value != null && value.Count > 0) - { - this.IsEmpty = false; - } - } - - public void WriteProperty(string name, IDictionary value) - { - if (value != null && value.Count > 0) - { - this.IsEmpty = false; - } - } - - public void WritePropertyName(string name) - { - } - - public void WriteRawValue(object value) - { - if (value != null) - { - this.IsEmpty = false; - } - } - } } -} +} \ No newline at end of file diff --git a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/JsonSerializer.cs b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/JsonSerializer.cs index 71ed3f126e..ae3c00c991 100644 --- a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/JsonSerializer.cs +++ b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/JsonSerializer.cs @@ -10,8 +10,6 @@ using System.Text; using Microsoft.ApplicationInsights.Channel; using Microsoft.ApplicationInsights.DataContracts; - using Microsoft.ApplicationInsights.Extensibility.Implementation.External; - using Microsoft.ApplicationInsights.Extensibility.Implementation.Platform; using Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing; /// @@ -148,85 +146,6 @@ internal static string SerializeAsString(ITelemetry telemetry) return SerializeAsString(new ITelemetry[] { telemetry }); } - #region Exception Serializer helper - - private static void SerializeExceptions(IEnumerable exceptions, IJsonWriter writer) - { - int exceptionArrayIndex = 0; - - foreach (ExceptionDetails exceptionDetails in exceptions) - { - if (exceptionArrayIndex++ != 0) - { - writer.WriteComma(); - } - - writer.WriteStartObject(); - writer.WriteProperty("id", exceptionDetails.id); - if (exceptionDetails.outerId != 0) - { - writer.WriteProperty("outerId", exceptionDetails.outerId); - } - - writer.WriteProperty( - "typeName", - Utils.PopulateRequiredStringValue(exceptionDetails.typeName, "typeName", typeof(ExceptionTelemetry).FullName)); - writer.WriteProperty( - "message", - Utils.PopulateRequiredStringValue(exceptionDetails.message, "message", typeof(ExceptionTelemetry).FullName)); - - if (exceptionDetails.hasFullStack) - { - writer.WriteProperty("hasFullStack", exceptionDetails.hasFullStack); - } - - writer.WriteProperty("stack", exceptionDetails.stack); - - if (exceptionDetails.parsedStack.Count > 0) - { - writer.WritePropertyName("parsedStack"); - - writer.WriteStartArray(); - - int stackFrameArrayIndex = 0; - - foreach (StackFrame frame in exceptionDetails.parsedStack) - { - if (stackFrameArrayIndex++ != 0) - { - writer.WriteComma(); - } - - writer.WriteStartObject(); - SerializeStackFrame(frame, writer); - writer.WriteEndObject(); - } - - writer.WriteEndArray(); - } - - writer.WriteEndObject(); - } - } - - private static void SerializeStackFrame(StackFrame frame, IJsonWriter writer) - { - writer.WriteProperty("level", frame.level); - writer.WriteProperty( - "method", - Utils.PopulateRequiredStringValue(frame.method, "StackFrameMethod", typeof(ExceptionTelemetry).FullName)); - writer.WriteProperty("assembly", frame.assembly); - writer.WriteProperty("fileName", frame.fileName); - - // 0 means it is unavailable - if (frame.line != 0) - { - writer.WriteProperty("line", frame.line); - } - } - - #endregion Exception Serializer helper - /// /// Creates a GZIP compression stream that wraps . For windows phone 8.0 it returns . /// @@ -235,66 +154,107 @@ private static Stream CreateCompressedStream(Stream stream) return new GZipStream(stream, CompressionMode.Compress); } - private static void SerializeTelemetryItem(ITelemetry telemetryItem, JsonWriter jsonWriter) + private static void SerializeTelemetryItem(ITelemetry telemetryItem, JsonSerializationWriter jsonSerializationWriter) { + jsonSerializationWriter.WriteStartObject(); + if (telemetryItem is EventTelemetry) { EventTelemetry eventTelemetry = telemetryItem as EventTelemetry; - SerializeEventTelemetry(eventTelemetry, jsonWriter); + Utils.CopyDictionary(telemetryItem.Context.GlobalProperties, eventTelemetry.Data.properties); + + SerializeHelper(telemetryItem, jsonSerializationWriter, eventTelemetry.BaseType, EventTelemetry.TelemetryName); } else if (telemetryItem is ExceptionTelemetry) { - ExceptionTelemetry exceptionTelemetry = telemetryItem as ExceptionTelemetry; - SerializeExceptionTelemetry(exceptionTelemetry, jsonWriter); + ExceptionTelemetry exTelemetry = telemetryItem as ExceptionTelemetry; + Utils.CopyDictionary(telemetryItem.Context.GlobalProperties, exTelemetry.Data.Data.properties); + + SerializeHelper(telemetryItem, jsonSerializationWriter, exTelemetry.BaseType, ExceptionTelemetry.TelemetryName); } else if (telemetryItem is MetricTelemetry) { - MetricTelemetry metricTelemetry = telemetryItem as MetricTelemetry; - SerializeMetricTelemetry(metricTelemetry, jsonWriter); + MetricTelemetry mTelemetry = telemetryItem as MetricTelemetry; + Utils.CopyDictionary(telemetryItem.Context.GlobalProperties, mTelemetry.Data.properties); + + SerializeHelper(telemetryItem, jsonSerializationWriter, mTelemetry.BaseType, MetricTelemetry.TelemetryName); } else if (telemetryItem is PageViewTelemetry) { - PageViewTelemetry pageViewTelemetry = telemetryItem as PageViewTelemetry; - SerializePageViewTelemetry(pageViewTelemetry, jsonWriter); + PageViewTelemetry pvTelemetry = telemetryItem as PageViewTelemetry; + Utils.CopyDictionary(telemetryItem.Context.GlobalProperties, pvTelemetry.Data.properties); + + SerializeHelper(telemetryItem, jsonSerializationWriter, pvTelemetry.BaseType, PageViewTelemetry.TelemetryName); + } + else if (telemetryItem is PageViewPerformanceTelemetry) + { + PageViewPerformanceTelemetry pvptelemetry = telemetryItem as PageViewPerformanceTelemetry; + Utils.CopyDictionary(telemetryItem.Context.GlobalProperties, pvptelemetry.Data.properties); + + SerializeHelper(telemetryItem, jsonSerializationWriter, PageViewPerformanceTelemetry.BaseType, PageViewPerformanceTelemetry.TelemetryName); } else if (telemetryItem is DependencyTelemetry) { - DependencyTelemetry remoteDependencyTelemetry = telemetryItem as DependencyTelemetry; - SerializeDependencyTelemetry(remoteDependencyTelemetry, jsonWriter); + DependencyTelemetry depTelemetry = telemetryItem as DependencyTelemetry; + Utils.CopyDictionary(telemetryItem.Context.GlobalProperties, depTelemetry.InternalData.properties); + + SerializeHelper(telemetryItem, jsonSerializationWriter, depTelemetry.BaseType, DependencyTelemetry.TelemetryName); } else if (telemetryItem is RequestTelemetry) { - RequestTelemetry requestTelemetry = telemetryItem as RequestTelemetry; - SerializeRequestTelemetry(requestTelemetry, jsonWriter); + RequestTelemetry reqTelemetry = telemetryItem as RequestTelemetry; + Utils.CopyDictionary(telemetryItem.Context.GlobalProperties, reqTelemetry.Data.properties); + + SerializeHelper(telemetryItem, jsonSerializationWriter, reqTelemetry.BaseType, RequestTelemetry.TelemetryName); } #pragma warning disable 618 + else if (telemetryItem is PerformanceCounterTelemetry) + { + PerformanceCounterTelemetry pcTelemetry = telemetryItem as PerformanceCounterTelemetry; + Utils.CopyDictionary(telemetryItem.Context.GlobalProperties, pcTelemetry.Properties); + + SerializeHelper(telemetryItem, jsonSerializationWriter, pcTelemetry.Data.BaseType, MetricTelemetry.TelemetryName); + } else if (telemetryItem is SessionStateTelemetry) { - EventTelemetry telemetry = (telemetryItem as SessionStateTelemetry).Data; - SerializeEventTelemetry(telemetry, jsonWriter); + SessionStateTelemetry ssTelemetry = telemetryItem as SessionStateTelemetry; + SerializeHelper(telemetryItem, jsonSerializationWriter, ssTelemetry.Data.BaseType, EventTelemetry.TelemetryName); } #pragma warning restore 618 - else if (telemetryItem is TraceTelemetry) + else if (telemetryItem is TraceTelemetry) { TraceTelemetry traceTelemetry = telemetryItem as TraceTelemetry; - SerializeTraceTelemetry(traceTelemetry, jsonWriter); - } -#pragma warning disable 618 - else if (telemetryItem is PerformanceCounterTelemetry) - { - MetricTelemetry telemetry = (telemetryItem as PerformanceCounterTelemetry).Data; - SerializeMetricTelemetry(telemetry, jsonWriter); - } + Utils.CopyDictionary(telemetryItem.Context.GlobalProperties, traceTelemetry.Data.properties); + + SerializeHelper(telemetryItem, jsonSerializationWriter, traceTelemetry.BaseType, TraceTelemetry.TelemetryName); + } else if (telemetryItem is AvailabilityTelemetry) { AvailabilityTelemetry availabilityTelemetry = telemetryItem as AvailabilityTelemetry; - SerializeAvailability(availabilityTelemetry, jsonWriter); + Utils.CopyDictionary(telemetryItem.Context.GlobalProperties, availabilityTelemetry.Data.properties); + + SerializeHelper(telemetryItem, jsonSerializationWriter, availabilityTelemetry.BaseType, AvailabilityTelemetry.TelemetryName); } else { - string msg = string.Format(CultureInfo.InvariantCulture, "Unknown telemetry type: {0}", telemetryItem.GetType()); + string msg = string.Format(CultureInfo.InvariantCulture, "Unknown telemetry type: {0}", telemetryItem.GetType()); CoreEventSource.Log.LogVerbose(msg); } + + jsonSerializationWriter.WriteEndObject(); + } + + private static void SerializeHelper(ITelemetry telemetryItem, JsonSerializationWriter jsonSerializationWriter, string baseType, string telemetryName) + { + jsonSerializationWriter.WriteProperty("name", telemetryItem.WriteTelemetryName(telemetryName)); + telemetryItem.WriteEnvelopeProperties(jsonSerializationWriter); + jsonSerializationWriter.WriteStartObject("data"); + jsonSerializationWriter.WriteProperty("baseType", baseType); + jsonSerializationWriter.WriteStartObject("baseData"); + telemetryItem.SerializeData(jsonSerializationWriter); + jsonSerializationWriter.WriteEndObject(); // baseData + jsonSerializationWriter.WriteProperty("extension", telemetryItem.Extension); + jsonSerializationWriter.WriteEndObject(); // data } /// @@ -302,7 +262,8 @@ private static void SerializeTelemetryItem(ITelemetry telemetryItem, JsonWriter /// private static void SeializeToStream(IEnumerable telemetryItems, TextWriter streamWriter) { - JsonWriter jsonWriter = new JsonWriter(streamWriter); + // JsonWriter jsonWriter = new JsonWriter(streamWriter); + JsonSerializationWriter jsonSerializationWriter = new JsonSerializationWriter(streamWriter); int telemetryCount = 0; foreach (ITelemetry telemetryItem in telemetryItems) @@ -314,314 +275,8 @@ private static void SeializeToStream(IEnumerable telemetryItems, Tex telemetryItem.Context.SanitizeGlobalProperties(); telemetryItem.Sanitize(); - SerializeTelemetryItem(telemetryItem, jsonWriter); - } - } - - #region Serialize methods for each ITelemetry implementation - - private static void SerializeEventTelemetry(EventTelemetry eventTelemetry, JsonWriter writer) - { - writer.WriteStartObject(); - - eventTelemetry.WriteTelemetryName(writer, EventTelemetry.TelemetryName); - eventTelemetry.WriteEnvelopeProperties(writer); - writer.WritePropertyName("data"); - { - writer.WriteStartObject(); - - writer.WriteProperty("baseType", eventTelemetry.BaseType); - writer.WritePropertyName("baseData"); - { - writer.WriteStartObject(); - - writer.WriteProperty("ver", eventTelemetry.Data.ver); - writer.WriteProperty("name", eventTelemetry.Data.name); - writer.WriteProperty("measurements", eventTelemetry.Data.measurements); - Utils.CopyDictionary(eventTelemetry.Context.GlobalProperties, eventTelemetry.Data.properties); - writer.WriteProperty("properties", eventTelemetry.Data.properties); - writer.WriteEndObject(); - } - - writer.WriteEndObject(); - } - - writer.WriteEndObject(); - } - - private static void SerializeExceptionTelemetry(ExceptionTelemetry exceptionTelemetry, JsonWriter writer) - { - writer.WriteStartObject(); - - exceptionTelemetry.WriteTelemetryName(writer, ExceptionTelemetry.TelemetryName); - exceptionTelemetry.WriteEnvelopeProperties(writer); - writer.WritePropertyName("data"); - { - writer.WriteStartObject(); - - writer.WriteProperty("baseType", exceptionTelemetry.BaseType); - writer.WritePropertyName("baseData"); - { - writer.WriteStartObject(); - - writer.WriteProperty("ver", exceptionTelemetry.Data.ver); - writer.WriteProperty("problemId", exceptionTelemetry.Data.problemId); - Utils.CopyDictionary(exceptionTelemetry.Context.GlobalProperties, exceptionTelemetry.Data.properties); - writer.WriteProperty("properties", exceptionTelemetry.Data.properties); - writer.WriteProperty("measurements", exceptionTelemetry.Data.measurements); - writer.WritePropertyName("exceptions"); - { - writer.WriteStartArray(); - - SerializeExceptions(exceptionTelemetry.Exceptions, writer); - - writer.WriteEndArray(); - } - - if (exceptionTelemetry.Data.severityLevel.HasValue) - { - writer.WriteProperty("severityLevel", exceptionTelemetry.Data.severityLevel.Value.ToString()); - } - - writer.WriteEndObject(); - } - - writer.WriteEndObject(); + SerializeTelemetryItem(telemetryItem, jsonSerializationWriter); } - - writer.WriteEndObject(); - } - - private static void SerializeMetricTelemetry(MetricTelemetry metricTelemetry, JsonWriter writer) - { - writer.WriteStartObject(); - - metricTelemetry.WriteTelemetryName(writer, MetricTelemetry.TelemetryName); - metricTelemetry.WriteEnvelopeProperties(writer); - writer.WritePropertyName("data"); - { - writer.WriteStartObject(); - - // TODO: MetricTelemetry should write type as this.data.baseType once Common Schema 2.0 compliant. - writer.WriteProperty("baseType", metricTelemetry.BaseType); - writer.WritePropertyName("baseData"); - { - writer.WriteStartObject(); - - writer.WriteProperty("ver", metricTelemetry.Data.ver); - writer.WritePropertyName("metrics"); - { - writer.WriteStartArray(); - writer.WriteStartObject(); - - string metricNamespace = metricTelemetry.Metric.ns; - if (false == String.IsNullOrEmpty(metricNamespace)) - { - writer.WriteProperty("ns", metricNamespace); - } - - writer.WriteProperty("name", metricTelemetry.Metric.name); - writer.WriteProperty("kind", metricTelemetry.Metric.kind.ToString()); - writer.WriteProperty("value", metricTelemetry.Metric.value); - writer.WriteProperty("count", metricTelemetry.Metric.count); - writer.WriteProperty("min", metricTelemetry.Metric.min); - writer.WriteProperty("max", metricTelemetry.Metric.max); - writer.WriteProperty("stdDev", metricTelemetry.Metric.stdDev); - writer.WriteEndObject(); - writer.WriteEndArray(); - } - - Utils.CopyDictionary(metricTelemetry.Context.GlobalProperties, metricTelemetry.Data.properties); - writer.WriteProperty("properties", metricTelemetry.Data.properties); - - writer.WriteEndObject(); - } - - writer.WriteEndObject(); - } - - writer.WriteEndObject(); - } - - private static void SerializePageViewTelemetry(PageViewTelemetry pageViewTelemetry, JsonWriter writer) - { - writer.WriteStartObject(); - - pageViewTelemetry.WriteTelemetryName(writer, PageViewTelemetry.TelemetryName); - pageViewTelemetry.WriteEnvelopeProperties(writer); - writer.WritePropertyName("data"); - { - writer.WriteStartObject(); - - // TODO: MetricTelemetry should write type as this.data.baseType once Common Schema 2.0 compliant. - writer.WriteProperty("baseType", pageViewTelemetry.BaseType); - writer.WritePropertyName("baseData"); - { - writer.WriteStartObject(); - - writer.WriteProperty("ver", pageViewTelemetry.Data.ver); - writer.WriteProperty("name", pageViewTelemetry.Data.name); - writer.WriteProperty("url", pageViewTelemetry.Data.url); - writer.WriteProperty("duration", pageViewTelemetry.Data.duration); - writer.WriteProperty("measurements", pageViewTelemetry.Data.measurements); - Utils.CopyDictionary(pageViewTelemetry.Context.GlobalProperties, pageViewTelemetry.Data.properties); - writer.WriteProperty("properties", pageViewTelemetry.Data.properties); - - writer.WriteEndObject(); - } - - writer.WriteEndObject(); - } - - writer.WriteEndObject(); - } - - private static void SerializeDependencyTelemetry(DependencyTelemetry dependencyTelemetry, JsonWriter writer) - { - writer.WriteStartObject(); - - dependencyTelemetry.WriteTelemetryName(writer, DependencyTelemetry.TelemetryName); - dependencyTelemetry.WriteEnvelopeProperties(writer); - writer.WritePropertyName("data"); - { - writer.WriteStartObject(); - - writer.WriteProperty("baseType", dependencyTelemetry.BaseType); - writer.WritePropertyName("baseData"); - { - writer.WriteStartObject(); - - writer.WriteProperty("ver", dependencyTelemetry.InternalData.ver); - writer.WriteProperty("name", dependencyTelemetry.InternalData.name); - writer.WriteProperty("id", dependencyTelemetry.InternalData.id); - writer.WriteProperty("data", dependencyTelemetry.InternalData.data); - writer.WriteProperty("duration", dependencyTelemetry.InternalData.duration); - writer.WriteProperty("resultCode", dependencyTelemetry.InternalData.resultCode); - writer.WriteProperty("success", dependencyTelemetry.InternalData.success); - writer.WriteProperty("type", dependencyTelemetry.InternalData.type); - writer.WriteProperty("target", dependencyTelemetry.InternalData.target); - Utils.CopyDictionary(dependencyTelemetry.Context.GlobalProperties, dependencyTelemetry.InternalData.properties); - writer.WriteProperty("properties", dependencyTelemetry.InternalData.properties); - writer.WriteProperty("measurements", dependencyTelemetry.InternalData.measurements); - writer.WriteEndObject(); - } - - writer.WriteEndObject(); - } - - writer.WriteEndObject(); - } - - private static void SerializeRequestTelemetry(RequestTelemetry requestTelemetry, JsonWriter jsonWriter) - { - jsonWriter.WriteStartObject(); - - requestTelemetry.WriteTelemetryName(jsonWriter, RequestTelemetry.TelemetryName); - requestTelemetry.WriteEnvelopeProperties(jsonWriter); - jsonWriter.WritePropertyName("data"); - { - jsonWriter.WriteStartObject(); - - jsonWriter.WriteProperty("baseType", requestTelemetry.BaseType); - jsonWriter.WritePropertyName("baseData"); - { - jsonWriter.WriteStartObject(); - - jsonWriter.WriteProperty("ver", requestTelemetry.Data.ver); - jsonWriter.WriteProperty("id", requestTelemetry.Data.id); - jsonWriter.WriteProperty("source", requestTelemetry.Data.source); - jsonWriter.WriteProperty("name", requestTelemetry.Data.name); - jsonWriter.WriteProperty("duration", requestTelemetry.Duration); - jsonWriter.WriteProperty("success", requestTelemetry.Data.success); - jsonWriter.WriteProperty("responseCode", requestTelemetry.Data.responseCode); - jsonWriter.WriteProperty("url", requestTelemetry.Data.url); - jsonWriter.WriteProperty("measurements", requestTelemetry.Data.measurements); - Utils.CopyDictionary(requestTelemetry.Context.GlobalProperties, requestTelemetry.Data.properties); - jsonWriter.WriteProperty("properties", requestTelemetry.Data.properties); - - jsonWriter.WriteEndObject(); - } - - jsonWriter.WriteEndObject(); - } - - jsonWriter.WriteEndObject(); } - - private static void SerializeTraceTelemetry(TraceTelemetry traceTelemetry, JsonWriter writer) - { - writer.WriteStartObject(); - - traceTelemetry.WriteTelemetryName(writer, TraceTelemetry.TelemetryName); - traceTelemetry.WriteEnvelopeProperties(writer); - writer.WritePropertyName("data"); - { - writer.WriteStartObject(); - - // TODO: MetricTelemetry should write type as this.data.baseType once Common Schema 2.0 compliant. - writer.WriteProperty("baseType", traceTelemetry.BaseType); - writer.WritePropertyName("baseData"); - { - writer.WriteStartObject(); - - writer.WriteProperty("ver", traceTelemetry.Data.ver); - writer.WriteProperty("message", traceTelemetry.Message); - - if (traceTelemetry.SeverityLevel.HasValue) - { - writer.WriteProperty("severityLevel", traceTelemetry.SeverityLevel.Value.ToString()); - } - - Utils.CopyDictionary(traceTelemetry.Context.GlobalProperties, traceTelemetry.Data.properties); - writer.WriteProperty("properties", traceTelemetry.Properties); // TODO: handle case where the property dictionary doesn't need to be instantiated. - - writer.WriteEndObject(); - } - - writer.WriteEndObject(); - } - - writer.WriteEndObject(); - } - - /// - /// Serializes this object in JSON format. - /// - private static void SerializeAvailability(AvailabilityTelemetry availabilityTelemetry, JsonWriter writer) - { - writer.WriteStartObject(); - - availabilityTelemetry.WriteTelemetryName(writer, AvailabilityTelemetry.TelemetryName); - availabilityTelemetry.WriteEnvelopeProperties(writer); - writer.WritePropertyName("data"); - { - writer.WriteStartObject(); - - writer.WriteProperty("baseType", availabilityTelemetry.BaseType); - writer.WritePropertyName("baseData"); - { - writer.WriteStartObject(); - - writer.WriteProperty("ver", availabilityTelemetry.Data.ver); - writer.WriteProperty("id", availabilityTelemetry.Data.id); - writer.WriteProperty("name", availabilityTelemetry.Data.name); - writer.WriteProperty("duration", availabilityTelemetry.Duration); - writer.WriteProperty("success", availabilityTelemetry.Data.success); - writer.WriteProperty("runLocation", availabilityTelemetry.Data.runLocation); - writer.WriteProperty("message", availabilityTelemetry.Data.message); - Utils.CopyDictionary(availabilityTelemetry.Context.GlobalProperties, availabilityTelemetry.Data.properties); - writer.WriteProperty("properties", availabilityTelemetry.Data.properties); - writer.WriteProperty("measurements", availabilityTelemetry.Data.measurements); - - writer.WriteEndObject(); - } - - writer.WriteEndObject(); - } - - writer.WriteEndObject(); - } - - #endregion Serialize methods for each ITelemetry implementation } } diff --git a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/OperationTelemetry.cs b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/OperationTelemetry.cs index f4db060d5d..c5c5e5189c 100644 --- a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/OperationTelemetry.cs +++ b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/OperationTelemetry.cs @@ -74,6 +74,11 @@ public DateTimeOffset StartTime /// public abstract string Sequence { get; set; } + /// + /// Gets or sets gets the extension used to extend this telemetry instance using new strong typed object. + /// + public abstract IExtension Extension { get; set; } + /// /// Gets or sets Time in StopWatch ticks representing begin time of the operation. Used internally /// for calculating duration between begin and end. @@ -94,6 +99,9 @@ void ITelemetry.Sanitize() /// A cloned instance. public abstract ITelemetry DeepClone(); + /// + public abstract void SerializeData(ISerializationWriter serializationWriter); + /// /// Sets operation Id. /// diff --git a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/RichPayloadEventSource.Keywords.cs b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/RichPayloadEventSource.Keywords.cs index 8f3d2c1a5e..c92cde86d4 100644 --- a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/RichPayloadEventSource.Keywords.cs +++ b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/RichPayloadEventSource.Keywords.cs @@ -66,6 +66,11 @@ public sealed class Keywords /// Keyword for operations (Start/Stop). /// public const EventKeywords Operations = (EventKeywords)0x400; + + /// + /// Keyword for page view performance. + /// + public const EventKeywords PageViewPerformance = (EventKeywords)0x800; } } } diff --git a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/RichPayloadEventSource.TelemetryHandler.cs b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/RichPayloadEventSource.TelemetryHandler.cs index ce26da562a..923a85c210 100644 --- a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/RichPayloadEventSource.TelemetryHandler.cs +++ b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/RichPayloadEventSource.TelemetryHandler.cs @@ -73,6 +73,9 @@ private Dictionary> CreateTelemetryHandlers(EventSource // PageView telemetryHandlers.Add(typeof(PageViewTelemetry), this.CreateHandlerForPageViewTelemetry(eventSource, writeGenericMethod, eventSourceOptionsType, eventSourceOptionsKeywordsProperty)); + // PageView + telemetryHandlers.Add(typeof(PageViewPerformanceTelemetry), this.CreateHandlerForPageViewPerformanceTelemetry(eventSource, writeGenericMethod, eventSourceOptionsType, eventSourceOptionsKeywordsProperty)); + #pragma warning disable 618 // SessionState telemetryHandlers.Add(typeof(SessionStateTelemetry), this.CreateHandlerForSessionStateTelemetry(eventSource, writeGenericMethod, eventSourceOptionsType, eventSourceOptionsKeywordsProperty)); @@ -502,7 +505,7 @@ private Action CreateHandlerForExceptionTelemetry(EventSource eventS eventSourceOptionsKeywordsProperty.SetValue(eventSourceOptions, keywords); var dummyExceptionData = new ExceptionData(); var dummyExceptionDetails = new ExceptionDetails(); - var dummyStackFrame = new StackFrame(); + var dummyStackFrame = new External.StackFrame(); var writeMethod = writeGenericMethod.MakeGenericMethod(new { PartA_iKey = this.dummyPartAiKeyValue, @@ -550,7 +553,7 @@ private Action CreateHandlerForExceptionTelemetry(EventSource eventS { item.Sanitize(); var telemetryItem = item as ExceptionTelemetry; - var data = telemetryItem.Data; + var data = telemetryItem.Data.Data; var extendedData = new { // The properties and layout should be the same as the anonymous type in the above MakeGenericMethod @@ -722,6 +725,64 @@ private Action CreateHandlerForPageViewTelemetry(EventSource eventSo }; } + /// + /// Create handler for page view performance telemetry. + /// + private Action CreateHandlerForPageViewPerformanceTelemetry(EventSource eventSource, MethodInfo writeGenericMethod, Type eventSourceOptionsType, PropertyInfo eventSourceOptionsKeywordsProperty) + { + var eventSourceOptions = Activator.CreateInstance(eventSourceOptionsType); + var keywords = Keywords.PageViews; + eventSourceOptionsKeywordsProperty.SetValue(eventSourceOptions, keywords); + var dummyPageViewPerfData = new PageViewPerfData(); + var writeMethod = writeGenericMethod.MakeGenericMethod(new + { + PartA_iKey = this.dummyPartAiKeyValue, + PartA_Tags = this.dummyPartATagsValue, + PartB_PageViewPerfData = new + { + // The properties and layout should be the same as PageViewPerfData_types.cs (EventData_types.cs) + dummyPageViewPerfData.perfTotal, + dummyPageViewPerfData.networkConnect, + dummyPageViewPerfData.sentRequest, + dummyPageViewPerfData.receivedResponse, + dummyPageViewPerfData.domProcessing, + dummyPageViewPerfData.url, + dummyPageViewPerfData.duration, + dummyPageViewPerfData.ver, + dummyPageViewPerfData.name, + dummyPageViewPerfData.properties, + dummyPageViewPerfData.measurements, + } + }.GetType()); + + return (item) => + { + if (this.EventSourceInternal.IsEnabled(EventLevel.Verbose, keywords)) + { + item.Sanitize(); + var telemetryItem = item as PageViewTelemetry; + var data = telemetryItem.Data; + var extendedData = new + { + // The properties and layout should be the same as the anonymous type in the above MakeGenericMethod + PartA_iKey = telemetryItem.Context.InstrumentationKey, + PartA_Tags = telemetryItem.Context.SanitizedTags, + PartB_PageViewPerfData = new + { + data.url, + data.duration, + data.ver, + data.name, + data.properties, + data.measurements, + } + }; + + writeMethod.Invoke(eventSource, new object[] { PageViewTelemetry.TelemetryName, eventSourceOptions, extendedData }); + } + }; + } + /// /// Create handler for session state telemetry. /// diff --git a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/RichPayloadEventSource.cs b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/RichPayloadEventSource.cs index 529c7843ec..1240eee405 100644 --- a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/RichPayloadEventSource.cs +++ b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/RichPayloadEventSource.cs @@ -144,7 +144,7 @@ public void Process(ITelemetry item) ExceptionTelemetry.TelemetryName, telemetryItem.Context.InstrumentationKey, telemetryItem.Context.SanitizedTags, - telemetryItem.Data, + telemetryItem.Data.Data, telemetryItem.Context.Flags, Keywords.Exceptions); } @@ -184,6 +184,23 @@ public void Process(ITelemetry item) telemetryItem.Context.Flags, Keywords.PageViews); } + else if (item is PageViewPerformanceTelemetry) + { + if (!this.EventSourceInternal.IsEnabled(EventLevel.Verbose, Keywords.PageViewPerformance)) + { + return; + } + + item.Sanitize(); + var telemetryItem = item as PageViewPerformanceTelemetry; + this.WriteEvent( + PageViewPerformanceTelemetry.TelemetryName, + telemetryItem.Context.InstrumentationKey, + telemetryItem.Context.SanitizedTags, + telemetryItem.Data, + telemetryItem.Context.Flags, + Keywords.PageViewPerformance); + } #pragma warning disable 618 else if (item is SessionStateTelemetry) { diff --git a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/Telemetry.cs b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/Telemetry.cs index 632b5c305d..0fb91713be 100644 --- a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/Telemetry.cs +++ b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/Telemetry.cs @@ -7,7 +7,7 @@ internal static class Telemetry { - public static void WriteEnvelopeProperties(this ITelemetry telemetry, IJsonWriter json) + public static void WriteEnvelopeProperties(this ITelemetry telemetry, ISerializationWriter json) { json.WriteProperty("time", telemetry.Timestamp.UtcDateTime.ToString("o", CultureInfo.InvariantCulture)); @@ -25,7 +25,7 @@ public static void WriteEnvelopeProperties(this ITelemetry telemetry, IJsonWrite WriteTelemetryContext(json, telemetry.Context); } - public static void WriteTelemetryName(this ITelemetry telemetry, IJsonWriter json, string telemetryName) + public static string WriteTelemetryName(this ITelemetry telemetry, string telemetryName) { // A different event name prefix is sent for normal mode and developer mode. bool isDevMode = false; @@ -44,10 +44,11 @@ public static void WriteTelemetryName(this ITelemetry telemetry, IJsonWriter jso isDevMode ? Constants.DevModeTelemetryNamePrefix : Constants.TelemetryNamePrefix, NormalizeInstrumentationKey(telemetry.Context.InstrumentationKey), telemetryName); - json.WriteProperty("name", eventName); + + return eventName; } - public static void WriteTelemetryContext(IJsonWriter json, TelemetryContext context) + public static void WriteTelemetryContext(ISerializationWriter json, TelemetryContext context) { if (context != null) { diff --git a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/TelemetryConfigurationFactory.cs b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/TelemetryConfigurationFactory.cs index 107eaab0f7..0847ccee4b 100644 --- a/src/Microsoft.ApplicationInsights/Extensibility/Implementation/TelemetryConfigurationFactory.cs +++ b/src/Microsoft.ApplicationInsights/Extensibility/Implementation/TelemetryConfigurationFactory.cs @@ -411,7 +411,16 @@ private static void LoadInstanceFromValue(XElement definition, Type expectedType } else { - instance = Convert.ChangeType(valueString, expectedType, CultureInfo.InvariantCulture); + if (valueString.IndexOf("0x", StringComparison.OrdinalIgnoreCase) == 0) + { + CultureInfo provider = CultureInfo.InvariantCulture; + + instance = Int32.Parse(valueString.Remove(0, 2), NumberStyles.AllowHexSpecifier, provider); + } + else + { + instance = Convert.ChangeType(valueString, expectedType, CultureInfo.InvariantCulture); + } } } catch (InvalidCastException e) @@ -458,4 +467,4 @@ private static IEnumerable GetPropertyDefinitions(XElement instanceDef return attributeDefinitions.Concat(elementDefinitions); } } -} \ No newline at end of file +} diff --git a/src/Microsoft.ApplicationInsights/Microsoft.ApplicationInsights.csproj b/src/Microsoft.ApplicationInsights/Microsoft.ApplicationInsights.csproj index 2f8e05d4ab..8e62f5ffb8 100644 --- a/src/Microsoft.ApplicationInsights/Microsoft.ApplicationInsights.csproj +++ b/src/Microsoft.ApplicationInsights/Microsoft.ApplicationInsights.csproj @@ -52,10 +52,12 @@ All + All - + + All @@ -69,11 +71,11 @@ - PublicAPI.Shipped.txt + PublicAPI.Shipped.txt - PublicAPI.Unshipped.txt - + PublicAPI.Unshipped.txt +