Enable ServerTelemetryChannel in .net core by the default (#530)
* Update versions * Switch to Server channel + port bond schemas * Change order * Fix remaining tests * Remaining test for performance counters * Add explicit DisableTestParallelization assembly attribute * Update changelog * Bring back initial condition for one of the tests * Disable tests with listener parallelization * lock object should be static... * Missed two tests to wrap in lock
This commit is contained in:
Родитель
3acf9bbe15
Коммит
c7b0358424
|
@ -40,11 +40,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FunctionalTestUtils20", "te
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MVCFramework.FunctionalTests", "test\MVCFramework.FunctionalTests\MVCFramework.FunctionalTests.csproj", "{1D5825CC-2EC9-43A1-BE32-778EFF5EAC80}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MVCFramework20.FunctionalTests", "test\MVCFramework20.FunctionalTests\MVCFramework20.FunctionalTests.csproj", "{51198C41-CD4A-4006-84D4-DE20A0A44363}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MVCFramework20.FunctionalTests", "test\MVCFramework20.FunctionalTests\MVCFramework20.FunctionalTests.csproj", "{51198C41-CD4A-4006-84D4-DE20A0A44363}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApi.FunctionalTests", "test\WebApi.FunctionalTests\WebApi.FunctionalTests.csproj", "{325C4ECE-BD4A-4CF2-BC80-FBD1024B5935}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApi20.FunctionalTests", "test\WebApi20.FunctionalTests\WebApi20.FunctionalTests.csproj", "{C3B3F515-0305-4809-A9A8-37FD80428F74}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApi20.FunctionalTests", "test\WebApi20.FunctionalTests\WebApi20.FunctionalTests.csproj", "{C3B3F515-0305-4809-A9A8-37FD80428F74}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApplicationInsightsTypes", "test\ApplicationInsightsTypes\ApplicationInsightsTypes.csproj", "{9DA7024F-216F-4FA5-9B6D-CE4216C2DD72}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
@ -92,6 +94,10 @@ Global
|
|||
{C3B3F515-0305-4809-A9A8-37FD80428F74}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C3B3F515-0305-4809-A9A8-37FD80428F74}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C3B3F515-0305-4809-A9A8-37FD80428F74}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9DA7024F-216F-4FA5-9B6D-CE4216C2DD72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9DA7024F-216F-4FA5-9B6D-CE4216C2DD72}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9DA7024F-216F-4FA5-9B6D-CE4216C2DD72}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9DA7024F-216F-4FA5-9B6D-CE4216C2DD72}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -108,6 +114,7 @@ Global
|
|||
{51198C41-CD4A-4006-84D4-DE20A0A44363} = {8B5230E5-8138-44D6-839F-DF9248F195EE}
|
||||
{325C4ECE-BD4A-4CF2-BC80-FBD1024B5935} = {8B5230E5-8138-44D6-839F-DF9248F195EE}
|
||||
{C3B3F515-0305-4809-A9A8-37FD80428F74} = {8B5230E5-8138-44D6-839F-DF9248F195EE}
|
||||
{9DA7024F-216F-4FA5-9B6D-CE4216C2DD72} = {8B5230E5-8138-44D6-839F-DF9248F195EE}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {047855A4-470F-43B1-8B74-69651DD6B8A6}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
- Project is upgraded to work with Visual Studio 2017. Also projects are modified to use csproj instead of project.json.
|
||||
- Adaptive sampling enabled for both - full framework and .NET Core applications.
|
||||
- ServerTelemetryChannel is enabled and set as default channel for both - full framework and .NET Core applications.
|
||||
|
||||
## Version 2.1.1
|
||||
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
import "Domain.bond"
|
||||
|
||||
namespace AI
|
||||
|
||||
[Description("Instances of AvailabilityData represent the result of executing an availability test.")]
|
||||
struct AvailabilityData
|
||||
: Domain
|
||||
{
|
||||
[Description("Schema version")]
|
||||
10: required int32 ver = 2;
|
||||
|
||||
[MaxStringLength("64")]
|
||||
[Description("Identifier of a test run. Use it to correlate steps of test run and telemetry generated by the service.")]
|
||||
[ActAsRequired("Renaming testRunId to id.")]
|
||||
21: required string id;
|
||||
|
||||
[MaxStringLength("1024")]
|
||||
[Description("Name of the test that these availability results represents.")]
|
||||
[ActAsRequired("Renaming testName to name.")]
|
||||
41: required string name;
|
||||
|
||||
[Description("Duration in TimeSpan 'G' (general long) format: d:hh:mm:ss.fffffff")]
|
||||
[CSType("TimeSpan")]
|
||||
50: required string duration;
|
||||
|
||||
[ActAsRequired("Renaming result to success.")]
|
||||
[Description("Success flag.")]
|
||||
61: required bool success;
|
||||
|
||||
[MaxStringLength("1024")]
|
||||
[Description("Name of the location where the test was run from.")]
|
||||
70: string runLocation;
|
||||
|
||||
[MaxStringLength("8192")]
|
||||
[Description("Diagnostic message for the result.")]
|
||||
80: string message;
|
||||
|
||||
[Description("Collection of custom properties.")]
|
||||
[MaxKeyLength("150")]
|
||||
[MaxValueLength("8192")]
|
||||
100: map<string, string> properties;
|
||||
|
||||
[Description("Collection of custom measurements.")]
|
||||
[MaxKeyLength("150")]
|
||||
200: map<string, double> measurements;
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
namespace AI
|
||||
|
||||
[Description("Data struct to contain only C section with custom fields.")]
|
||||
struct Base
|
||||
{
|
||||
[Name("ItemTypeName")]
|
||||
[Description("Name of item (B section) if any. If telemetry data is derived straight from this, this should be null.")]
|
||||
10: string baseType;
|
||||
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
|
||||
namespace AI
|
||||
|
||||
[ContextContract("Emit")]
|
||||
[PseudoType("JSMap")]
|
||||
struct ContextTagKeys
|
||||
{
|
||||
[Description("Application version. Information in the application context fields is always about the application that is sending the telemetry.")]
|
||||
[MaxStringLength("1024")]
|
||||
10: string ApplicationVersion = "ai.application.ver";
|
||||
|
||||
[Description("Unique client device id. Computer name in most cases.")]
|
||||
[MaxStringLength("1024")]
|
||||
100: string DeviceId = "ai.device.id";
|
||||
|
||||
[Description("Device locale using <language>-<REGION> pattern, following RFC 5646. Example 'en-US'.")]
|
||||
[MaxStringLength("64")]
|
||||
115: string DeviceLocale = "ai.device.locale";
|
||||
|
||||
[Description("Model of the device the end user of the application is using. Used for client scenarios. If this field is empty then it is derived from the user agent.")]
|
||||
[MaxStringLength("256")]
|
||||
120: string DeviceModel = "ai.device.model";
|
||||
|
||||
[Description("Client device OEM name taken from the browser.")]
|
||||
[MaxStringLength("256")]
|
||||
130: string DeviceOEMName = "ai.device.oemName";
|
||||
|
||||
[Description("Operating system name and version of the device the end user of the application is using. If this field is empty then it is derived from the user agent. Example 'Windows 10 Pro 10.0.10586.0'")]
|
||||
[MaxStringLength("256")]
|
||||
140: string DeviceOSVersion = "ai.device.osVersion";
|
||||
|
||||
[Description("The type of the device the end user of the application is using. Used primarily to distinguish JavaScript telemetry from server side telemetry. Examples: 'PC', 'Phone', 'Browser'. 'PC' is the default value.")]
|
||||
[MaxStringLength("64")]
|
||||
160: string DeviceType = "ai.device.type";
|
||||
|
||||
[Description("The IPv4 IP address of the client device. IPv6 is not currently supported. Information in the location context fields is always about the end user. When telemetry is sent from a service, the location context is about the user that initiated the operation in the service.")]
|
||||
[MaxStringLength("45")]
|
||||
200: string LocationIp = "ai.location.ip";
|
||||
|
||||
[Description("A unique identifier for the operation instance. The operation.id is created by either a request or a page view. All other telemetry sets this to the value for the containing request or page view. Operation.id is used for finding all the telemetry items for a specific operation instance.")]
|
||||
[MaxStringLength("128")]
|
||||
300: string OperationId = "ai.operation.id";
|
||||
|
||||
[Description("The name (group) of the operation. The operation.name is created by either a request or a page view. All other telemetry items set this to the value for the containing request or page view. Operation.name is used for finding all the telemetry items for a group of operations (i.e. 'GET Home/Index').")]
|
||||
[MaxStringLength("1024")]
|
||||
305: string OperationName = "ai.operation.name";
|
||||
|
||||
[Description("The unique identifier of the telemetry item's immediate parent.")]
|
||||
[MaxStringLength("128")]
|
||||
310: string OperationParentId = "ai.operation.parentId";
|
||||
|
||||
[Description("Name of synthetic source. Some telemetry from the application may represent a synthetic traffic. It may be web crawler indexing the web site, site availability tests or traces from diagnostic libraries like Application Insights SDK itself.")]
|
||||
[MaxStringLength("1024")]
|
||||
320: string OperationSyntheticSource = "ai.operation.syntheticSource";
|
||||
|
||||
[Description("The correlation vector is a light weight vector clock which can be used to identify and order related events across clients and services.")]
|
||||
[MaxStringLength("64")]
|
||||
330: string OperationCorrelationVector = "ai.operation.correlationVector";
|
||||
|
||||
[Description("Session ID - the instance of the user's interaction with the app. Information in the session context fields is always about the end user. When telemetry is sent from a service, the session context is about the user that initiated the operation in the service.")]
|
||||
[MaxStringLength("64")]
|
||||
400: string SessionId = "ai.session.id";
|
||||
|
||||
[Description("Boolean value indicating whether the session identified by ai.session.id is first for the user or not.")]
|
||||
[MaxStringLength("5")]
|
||||
[Question("Should it be marked as JSType-bool for breeze?")]
|
||||
405: string SessionIsFirst = "ai.session.isFirst";
|
||||
|
||||
[Description("In multi-tenant applications this is the account ID or name which the user is acting with. Examples may be subscription ID for Azure portal or blog name blogging platform.")]
|
||||
[MaxStringLength("1024")]
|
||||
505: string UserAccountId = "ai.user.accountId";
|
||||
|
||||
[Description("The browser's user agent string as reported by the browser. This property will be used to extract informaiton regarding the customer's browser but will not be stored. Use custom properties to store the original user agent.")]
|
||||
[MaxStringLength("2048")]
|
||||
510: string UserAgent = "ai.user.userAgent";
|
||||
|
||||
[Description("Anonymous user id. Represents the end user of the application. When telemetry is sent from a service, the user context is about the user that initiated the operation in the service.")]
|
||||
[MaxStringLength("128")]
|
||||
515: string UserId = "ai.user.id";
|
||||
|
||||
[Description("Authenticated user id. The opposite of ai.user.id, this represents the user with a friendly name. Since it's PII information it is not collected by default by most SDKs.")]
|
||||
[MaxStringLength("1024")]
|
||||
525: string UserAuthUserId = "ai.user.authUserId";
|
||||
|
||||
[Description("Name of the role the application is a part of. Maps directly to the role name in azure.")]
|
||||
[MaxStringLength("256")]
|
||||
705: string CloudRole = "ai.cloud.role";
|
||||
|
||||
[Description("Name of the instance where the application is running. Computer name for on-premisis, instance name for Azure.")]
|
||||
[MaxStringLength("256")]
|
||||
715: string CloudRoleInstance = "ai.cloud.roleInstance";
|
||||
|
||||
[Description("SDK version. See https://github.com/Microsoft/ApplicationInsights-Home/blob/master/SDK-AUTHORING.md#sdk-version-specification for information.")]
|
||||
[MaxStringLength("64")]
|
||||
1000: string InternalSdkVersion = "ai.internal.sdkVersion";
|
||||
|
||||
[Description("Agent version. Used to indicate the version of StatusMonitor installed on the computer if it is used for data collection.")]
|
||||
[MaxStringLength("64")]
|
||||
1001: string InternalAgentVersion = "ai.internal.agentVersion";
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import "Base.bond"
|
||||
|
||||
namespace AI
|
||||
|
||||
[Description("Data struct to contain both B and C sections.")]
|
||||
struct Data<TDomain>
|
||||
: Base
|
||||
{
|
||||
[Name("Item")]
|
||||
[Description("Container for data item (B section).")]
|
||||
20: required TDomain baseData;
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
import "DataPointType.bond"
|
||||
|
||||
namespace AI
|
||||
|
||||
[Description("Metric data single measurement.")]
|
||||
struct DataPoint
|
||||
{
|
||||
[Description("Name of the metric.")]
|
||||
[MaxStringLength("1024")]
|
||||
10: required string name;
|
||||
|
||||
[Description("Metric type.")]
|
||||
20: AI.DataPointType kind = Measurement;
|
||||
|
||||
[Description("Metric calculated value.")]
|
||||
30: required double value;
|
||||
|
||||
[Description("Metric weight of the aggregated metric. Should not be set for a measurement.")]
|
||||
40: nullable<int32> count;
|
||||
|
||||
[Description("Minimum value of the aggregated metric. Should not be set for a measurement.")]
|
||||
50: nullable<double> min;
|
||||
|
||||
[Description("Maximum value of the aggregated metric. Should not be set for a measurement.")]
|
||||
60: nullable<double> max;
|
||||
|
||||
[Description("Standard deviation of the aggregated metric. Should not be set for a measurement.")]
|
||||
70: nullable<double> stdDev;
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace AI
|
||||
|
||||
[Description("Type of the metric data measurement.")]
|
||||
enum DataPointType
|
||||
{
|
||||
Measurement,
|
||||
Aggregation,
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
namespace AI
|
||||
|
||||
[Description("The abstract common base of all domains.")]
|
||||
struct Domain
|
||||
{
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
import "Base.bond"
|
||||
|
||||
namespace AI
|
||||
|
||||
[Description("System variables for a telemetry item.")]
|
||||
struct Envelope
|
||||
{
|
||||
[Description("Envelope version. For internal use only. By assigning this the default, it will not be serialized within the payload unless changed to a value other than #1.")]
|
||||
[Name("SchemaVersion")]
|
||||
10: int32 ver = 1;
|
||||
|
||||
[Description("Type name of telemetry data item.")]
|
||||
[Name("DataTypeName")]
|
||||
[MaxStringLength("1024")]
|
||||
20: required string name;
|
||||
|
||||
[Description("Event date time when telemetry item was created. This is the wall clock time on the client when the event was generated. There is no guarantee that the client's time is accurate. This field must be formatted in UTC ISO 8601 format, with a trailing 'Z' character, as described publicly on https://en.wikipedia.org/wiki/ISO_8601#UTC. Note: the number of decimal seconds digits provided are variable (and unspecified). Consumers should handle this, i.e. managed code consumers should not use format 'O' for parsing as it specifies a fixed length. Example: 2009-06-15T13:45:30.0000000Z.")]
|
||||
[Name("DateTime")]
|
||||
[CSType("DateTimeOffset")]
|
||||
[JSType("Date")]
|
||||
[HockeyAppMinDateOffsetFromNow("2592000000")]
|
||||
[MinDateOffsetFromNow("172800000")]
|
||||
[MaxDateOffsetFromNow("7200000")]
|
||||
30: required string time;
|
||||
|
||||
[Name("SamplingRate")]
|
||||
[Description("Sampling rate used in application. This telemetry item represents 1 / sampleRate actual telemetry items.")]
|
||||
40: double sampleRate = 100.0;
|
||||
|
||||
[Description("Sequence field used to track absolute order of uploaded events.")]
|
||||
[Name("SequenceNumber")]
|
||||
[MaxStringLength("64")]
|
||||
50: string seq;
|
||||
|
||||
[Description("The application's instrumentation key.")]
|
||||
[Name("InstrumentationKey")]
|
||||
[MaxStringLength("40")]
|
||||
60: string iKey;
|
||||
|
||||
[Name("Tags")]
|
||||
[TypeAlias("ContextTagKeys")]
|
||||
[Description("Key/value collection of context properties. See ContextTagKeys for information on available properties.")]
|
||||
500: map<string, string> tags;
|
||||
|
||||
[Name("TelemetryData")]
|
||||
[Description("Telemetry data item.")]
|
||||
999: Base data;
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
import "Domain.bond"
|
||||
|
||||
namespace AI
|
||||
|
||||
[Description("Instances of Event represent structured event records that can be grouped and searched by their properties. Event data item also creates a metric of event count by name.")]
|
||||
struct EventData
|
||||
: Domain
|
||||
{
|
||||
[Description("Schema version")]
|
||||
10: required int32 ver = 2;
|
||||
|
||||
[MaxStringLength("512")]
|
||||
[Description("Event name. Keep it low cardinality to allow proper grouping and useful metrics.")]
|
||||
[Question("Why Custom Event name is shorter than Request name or dependency name?")]
|
||||
20: required string name;
|
||||
|
||||
[Description("Collection of custom properties.")]
|
||||
[MaxKeyLength("150")]
|
||||
[MaxValueLength("8192")]
|
||||
100: map<string, string> properties;
|
||||
|
||||
[Description("Collection of custom measurements.")]
|
||||
[MaxKeyLength("150")]
|
||||
200: map<string, double> measurements;
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
import "Domain.bond"
|
||||
import "ExceptionDetails.bond"
|
||||
import "SeverityLevel.bond"
|
||||
|
||||
namespace AI
|
||||
|
||||
[Description("An instance of Exception represents a handled or unhandled exception that occurred during execution of the monitored application.")]
|
||||
struct ExceptionData
|
||||
: Domain
|
||||
{
|
||||
[Description("Schema version")]
|
||||
10: required int32 ver = 2;
|
||||
|
||||
[Description("Exception chain - list of inner exceptions.")]
|
||||
50: required vector<ExceptionDetails> exceptions;
|
||||
|
||||
[Description("Severity level. Mostly used to indicate exception severity level when it is reported by logging library.")]
|
||||
60: nullable<AI.SeverityLevel> severityLevel;
|
||||
|
||||
[Description("Identifier of where the exception was thrown in code. Used for exceptions grouping. Typically a combination of exception type and a function from the call stack.")]
|
||||
[MaxStringLength("1024")]
|
||||
80: string problemId;
|
||||
|
||||
[Description("Collection of custom properties.")]
|
||||
[MaxKeyLength("150")]
|
||||
[MaxValueLength("8192")]
|
||||
100: map<string, string> properties;
|
||||
|
||||
[Description("Collection of custom measurements.")]
|
||||
[MaxKeyLength("150")]
|
||||
200: map<string, double> measurements;
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import "StackFrame.bond"
|
||||
|
||||
namespace AI
|
||||
|
||||
[Description("Exception details of the exception in a chain.")]
|
||||
struct ExceptionDetails
|
||||
{
|
||||
[Description("In case exception is nested (outer exception contains inner one), the id and outerId properties are used to represent the nesting.")]
|
||||
10: int32 id;
|
||||
|
||||
[Description("The value of outerId is a reference to an element in ExceptionDetails that represents the outer exception")]
|
||||
20: int32 outerId;
|
||||
|
||||
[Description("Exception type name.")]
|
||||
[MaxStringLength("1024")]
|
||||
30: required string typeName;
|
||||
|
||||
[Description("Exception message.")]
|
||||
[MaxStringLength("1024")]
|
||||
40: required string message;
|
||||
|
||||
[Description("Indicates if full exception stack is provided in the exception. The stack may be trimmed, such as in the case of a StackOverflow exception.")]
|
||||
50: bool hasFullStack = true;
|
||||
|
||||
[Description("Text describing the stack. Either stack or parsedStack should have a value.")]
|
||||
[MaxStringLength("32768")]
|
||||
60: string stack;
|
||||
|
||||
[Description("List of stack frames. Either stack or parsedStack should have a value.")]
|
||||
70: vector<StackFrame> parsedStack;
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import "Domain.bond"
|
||||
import "SeverityLevel.bond"
|
||||
|
||||
namespace AI
|
||||
|
||||
[Description("Instances of Message represent printf-like trace statements that are text-searched. Log4Net, NLog and other text-based log file entries are translated into intances of this type. The message does not have measurements.")]
|
||||
struct MessageData
|
||||
: Domain
|
||||
{
|
||||
[Description("Schema version")]
|
||||
10: required int32 ver = 2;
|
||||
|
||||
[MaxStringLength("32768")]
|
||||
[Description("Trace message")]
|
||||
20: required string message;
|
||||
|
||||
[Description("Trace severity level.")]
|
||||
30: nullable<AI.SeverityLevel> severityLevel;
|
||||
|
||||
[Description("Collection of custom properties.")]
|
||||
[MaxKeyLength("150")]
|
||||
[MaxValueLength("8192")]
|
||||
100: map<string, string> properties;
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import "Domain.bond"
|
||||
import "DataPoint.bond"
|
||||
|
||||
namespace AI
|
||||
|
||||
[Description("An instance of the Metric item is a list of measurements (single data points) and/or aggregations.")]
|
||||
struct MetricData
|
||||
: Domain
|
||||
{
|
||||
[Description("Schema version")]
|
||||
10: required int32 ver = 2;
|
||||
|
||||
[Description("List of metrics.")]
|
||||
20: required vector<DataPoint> metrics;
|
||||
|
||||
[Description("Collection of custom properties.")]
|
||||
[MaxKeyLength("150")]
|
||||
[MaxValueLength("8192")]
|
||||
100: map<string, string> properties;
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
import "EventData.bond"
|
||||
|
||||
namespace AI
|
||||
|
||||
[Description("An instance of PageView represents a generic action on a page like a button click. It is also the base type for PageView.")]
|
||||
[Alias("PageviewData;PageEventData")]
|
||||
struct PageViewData
|
||||
: EventData
|
||||
{
|
||||
[MaxStringLength("2048")]
|
||||
[Description("Request URL with all query string parameters")]
|
||||
10: string url;
|
||||
|
||||
[CSType("TimeSpan")]
|
||||
[Description("Request duration in TimeSpan 'G' (general long) format: d:hh:mm:ss.fffffff. For a page view (PageViewData), this is the duration. For a page view with performance information (PageViewPerfData), this is the page load time.")]
|
||||
20: string duration;
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
import "PageViewData.bond"
|
||||
|
||||
namespace AI
|
||||
|
||||
[Description("An instance of PageViewPerf represents: a page view with no performance data, a page view with performance data, or just the performance data of an earlier page request.")]
|
||||
[Alias("PageViewPerformanceData;PageviewPerformanceData")]
|
||||
struct PageViewPerfData
|
||||
: PageViewData
|
||||
{
|
||||
[Description("Performance total in TimeSpan 'G' (general long) format: d:hh:mm:ss.fffffff")]
|
||||
[CSType("TimeSpan")]
|
||||
10: string perfTotal;
|
||||
|
||||
[Description("Network connection time in TimeSpan 'G' (general long) format: d:hh:mm:ss.fffffff")]
|
||||
[CSType("TimeSpan")]
|
||||
20: string networkConnect;
|
||||
|
||||
[Description("Sent request time in TimeSpan 'G' (general long) format: d:hh:mm:ss.fffffff")]
|
||||
[CSType("TimeSpan")]
|
||||
30: string sentRequest;
|
||||
|
||||
[Description("Received response time in TimeSpan 'G' (general long) format: d:hh:mm:ss.fffffff")]
|
||||
[CSType("TimeSpan")]
|
||||
40: string receivedResponse;
|
||||
|
||||
[Description("DOM processing time in TimeSpan 'G' (general long) format: d:hh:mm:ss.fffffff")]
|
||||
[CSType("TimeSpan")]
|
||||
50: string domProcessing;
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
import "Domain.bond"
|
||||
|
||||
namespace AI
|
||||
|
||||
[Description("An instance of Remote Dependency represents an interaction of the monitored component with a remote component/service like SQL or an HTTP endpoint.")]
|
||||
struct RemoteDependencyData
|
||||
: Domain
|
||||
{
|
||||
[Description("Schema version")]
|
||||
10: required int32 ver = 2;
|
||||
|
||||
[MaxStringLength("1024")]
|
||||
[Description("Name of the command initiated with this dependency call. Low cardinality value. Examples are stored procedure name and URL path template.")]
|
||||
20: required string name;
|
||||
|
||||
[MaxStringLength("128")]
|
||||
[Description("Identifier of a dependency call instance. Used for correlation with the request telemetry item corresponding to this dependency call.")]
|
||||
30: string id;
|
||||
|
||||
[MaxStringLength("1024")]
|
||||
[Description("Result code of a dependency call. Examples are SQL error code and HTTP status code.")]
|
||||
40: string resultCode;
|
||||
|
||||
[CSType("TimeSpan")]
|
||||
[Description("Request duration in TimeSpan 'G' (general long) format: d:hh:mm:ss.fffffff.")]
|
||||
[ActAsRequired("Renaming value to duration.")]
|
||||
61: required string duration;
|
||||
|
||||
[Description("Indication of successfull or unsuccessfull call.")]
|
||||
120: bool success = true;
|
||||
|
||||
[MaxStringLength("8192")]
|
||||
[Description("Command initiated by this dependency call. Examples are SQL statement and HTTP URL's with all query parameters.")]
|
||||
151: string data;
|
||||
|
||||
[MaxStringLength("1024")]
|
||||
[Description("Dependency type name. Very low cardinality value for logical grouping of dependencies and interpretation of other fields like commandName and resultCode. Examples are SQL, Azure table, and HTTP.")]
|
||||
162: string type;
|
||||
|
||||
[MaxStringLength("1024")]
|
||||
[Description("Target site of a dependency call. Examples are server name, host address.")]
|
||||
161: string target;
|
||||
|
||||
[Description("Collection of custom properties.")]
|
||||
[MaxKeyLength("150")]
|
||||
[MaxValueLength("8192")]
|
||||
200: map<string, string> properties;
|
||||
|
||||
[Description("Collection of custom measurements.")]
|
||||
[MaxKeyLength("150")]
|
||||
300: map<string, double> measurements;
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
import "Domain.bond"
|
||||
|
||||
namespace AI
|
||||
|
||||
[Description("An instance of Request represents completion of an external request to the application to do work and contains a summary of that request execution and the results.")]
|
||||
struct RequestData
|
||||
: Domain
|
||||
{
|
||||
[Description("Schema version")]
|
||||
10: required int32 ver = 2;
|
||||
|
||||
[MaxStringLength("128")]
|
||||
[Description("Identifier of a request call instance. Used for correlation between request and other telemetry items.")]
|
||||
20: required string id;
|
||||
|
||||
[CSType("TimeSpan")]
|
||||
[Description("Request duration in TimeSpan 'G' (general long) format: d:hh:mm:ss.fffffff.")]
|
||||
50: required string duration;
|
||||
|
||||
[MaxStringLength("1024")]
|
||||
[Description("Result of a request execution. HTTP status code for HTTP requests.")]
|
||||
60: required string responseCode;
|
||||
|
||||
[Description("Indication of successfull or unsuccessfull call.")]
|
||||
70: required bool success;
|
||||
|
||||
[MaxStringLength("1024")]
|
||||
[Description("Name of the request. Represents code path taken to process request. Low cardinality value to allow better grouping of requests. For HTTP requests it represents the HTTP method and URL path template like 'GET /values/{id}'.")]
|
||||
30: string name;
|
||||
|
||||
[MaxStringLength("2048")]
|
||||
[Description("Request URL with all query string parameters.")]
|
||||
90: string url;
|
||||
|
||||
[Description("Collection of custom properties.")]
|
||||
[MaxKeyLength("150")]
|
||||
[MaxValueLength("8192")]
|
||||
100: map<string, string> properties;
|
||||
|
||||
[Description("Collection of custom measurements.")]
|
||||
[MaxKeyLength("150")]
|
||||
200: map<string, double> measurements;
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
namespace AI
|
||||
|
||||
[Description("Defines the level of severity for the event.")]
|
||||
enum SeverityLevel
|
||||
{
|
||||
Verbose,
|
||||
Information,
|
||||
Warning,
|
||||
Error,
|
||||
Critical,
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
namespace AI
|
||||
|
||||
[Description("Stack frame information.")]
|
||||
struct StackFrame
|
||||
{
|
||||
[Description("Level in the call stack. For the long stacks SDK may not report every function in a call stack.")]
|
||||
10: required int32 level;
|
||||
|
||||
[Description("Method name.")]
|
||||
[MaxStringLength("1024")]
|
||||
20: required string method;
|
||||
|
||||
[Description("Name of the assembly (dll, jar, etc.) containing this function.")]
|
||||
[MaxStringLength("1024")]
|
||||
30: string assembly;
|
||||
|
||||
[Description("File name or URL of the method implementation.")]
|
||||
[MaxStringLength("1024")]
|
||||
50: string fileName;
|
||||
|
||||
[Description("Line number of the code implementation.")]
|
||||
60: int32 line;
|
||||
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
$generatorPath = "C:\src\mseng\AppInsights-Common"
|
||||
$schemasPath = "C:\src\mseng\DataCollectionSchemas"
|
||||
$publicSchemaLocation = "https://raw.githubusercontent.com/Microsoft/ApplicationInsights-Home/master/EndpointSpecs/Schemas/Bond"
|
||||
$localPublicSchema = $false
|
||||
|
||||
|
||||
$currentDir = $scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
|
||||
#fix path
|
||||
$generatorPath = "$generatorPath\..\bin\Debug\BondSchemaGenerator\BondSchemaGenerator"
|
||||
$schemasPath = "$schemasPath\v2\Bond\"
|
||||
|
||||
|
||||
|
||||
function RegExReplace([string]$fileName, [string]$regex, [string]$replacement="")
|
||||
{
|
||||
$content = Get-Content $fileName
|
||||
$content = $content -creplace $regex,$replacement
|
||||
$content | Set-Content $fileName
|
||||
}
|
||||
|
||||
|
||||
#####################################################################
|
||||
## PUBLIC SCHEMA
|
||||
#####################################################################
|
||||
|
||||
mkdir -Force $currentDir\PublicSchema
|
||||
|
||||
del "$currentDir\PublicSchema\*.bond"
|
||||
|
||||
if ($localPublicSchema) {
|
||||
# Generate public schema using bond generator
|
||||
& "$generatorPath\BondSchemaGenerator.exe" -v -i "$schemasPath\AppInsightsTypes.bond" -i "$schemasPath\PerformanceCounterData.bond" -i "$schemasPath\SessionStateData.bond" -i "$schemasPath\ContextTagKeys.bond" -o "$currentDir\PublicSchema\" -e BondLanguage -t BondLayout -n test --flatten false
|
||||
} else {
|
||||
# Download public schema from the github
|
||||
@(
|
||||
"AvailabilityData.bond",
|
||||
"Base.bond",
|
||||
"ContextTagKeys.bond",
|
||||
"Data.bond",
|
||||
"DataPoint.bond",
|
||||
"DataPointType.bond",
|
||||
"Domain.bond",
|
||||
"Envelope.bond",
|
||||
"EventData.bond",
|
||||
"ExceptionData.bond",
|
||||
"ExceptionDetails.bond",
|
||||
"MessageData.bond",
|
||||
"MetricData.bond",
|
||||
"PageViewData.bond",
|
||||
"PageViewPerfData.bond",
|
||||
"RemoteDependencyData.bond",
|
||||
"RequestData.bond",
|
||||
"SeverityLevel.bond",
|
||||
"StackFrame.bond"
|
||||
) | ForEach-Object {
|
||||
$fileName = $_
|
||||
& Invoke-WebRequest -o "$currentDir\PublicSchema\$fileName" "$publicSchemaLocation/$fileName"
|
||||
RegExReplace "$currentDir\PublicSchema\$fileName" "`n" "`r`n"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#####################################################################
|
||||
## BOND-GENERATED CODE
|
||||
#####################################################################
|
||||
|
||||
mkdir -Force $currentDir\obj
|
||||
|
||||
Invoke-WebRequest -o "$currentDir\obj\nuget.exe" https://api.nuget.org/downloads/nuget.exe
|
||||
|
||||
|
||||
del $currentDir\obj\gbc\*
|
||||
|
||||
& "$currentDir\obj\nuget" install Bond.CSharp -Version 4.2.1 -OutputDirectory "$currentDir\obj\packages"
|
||||
|
||||
dir "$currentDir\PublicSchema" | ForEach-Object {
|
||||
& "$currentDir\obj\packages\Bond.CSharp.4.2.1\tools\gbc.exe" c# --collection-interfaces --using="DateTimeOffset=System.DateTimeOffset" --using="TimeSpan=System.TimeSpan" --using="Guid=System.Guid" -o "$currentDir\obj\gbc" $_.FullName
|
||||
}
|
||||
|
||||
del "$currentDir\obj\gbc\*_interfaces.cs"
|
||||
del "$currentDir\obj\gbc\*_services.cs"
|
||||
del "$currentDir\obj\gbc\*_proxies.cs"
|
||||
|
||||
|
||||
|
||||
#####################################################################
|
||||
## CLEAR BOND-GENERATED CODE OUT OF BOND REFERENCES
|
||||
#####################################################################
|
||||
|
||||
|
||||
dir "$currentDir\obj\gbc" | ForEach-Object {
|
||||
# Rename namespace from AI to Microsoft.ApplicationInsights.Extensibility.Implementation.External
|
||||
RegExReplace $_.FullName "(namespace AI)" "namespace Microsoft.ApplicationInsights.Extensibility.Implementation.External"
|
||||
RegExReplace $_.FullName "new Dictionary" "new ConcurrentDictionary"
|
||||
# Remove "using Bond" statements
|
||||
RegExReplace $_.FullName "using Bond.*"
|
||||
RegExReplace $_.FullName "using System.Collections.Generic;" "using System.Collections.Concurrent;`r`n using System.Collections.Generic;"
|
||||
# Remove all Bond attributes
|
||||
RegExReplace $_.FullName "\[global::Bond\..*\]"
|
||||
# Remove derivations from Microsoft.Telemetry.Domain
|
||||
RegExReplace $_.FullName ":\s*global::Microsoft\.Telemetry\.Domain"
|
||||
# Replace IBonded field definition with plain type field definition
|
||||
RegExReplace $_.FullName "global::Bond\.IBonded<([A-Za-z0-9_]+)>" '$1'
|
||||
# Remove the baseData field initializer
|
||||
RegExReplace $_.FullName "baseData\s*=.*;"
|
||||
# Remove the data field initializer
|
||||
RegExReplace $_.FullName "data\s*=.*;"
|
||||
# Make all public classes internal
|
||||
RegExReplace $_.FullName "(public partial class)" "internal partial class"
|
||||
# Make all public enums internal
|
||||
RegExReplace $_.FullName "(public enum)" "internal enum"
|
||||
# Change "= nothing" to "= null"
|
||||
RegExReplace $_.FullName "= nothing;" "= null;"
|
||||
}
|
||||
|
||||
|
||||
#####################################################################
|
||||
## COPY GENERATED FILES TO THE REPOSITORY
|
||||
#####################################################################
|
||||
|
||||
del "$currentDir\..\src\Core\Managed\Shared\Extensibility\Implementation\External\*_types.cs"
|
||||
|
||||
dir "$currentDir\obj\gbc\*_types.cs" | ForEach-Object {
|
||||
$fileName = $_
|
||||
copy $fileName "$currentDir\..\src\Core\Managed\Shared\Extensibility\Implementation\External\"
|
||||
}
|
|
@ -7,9 +7,9 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
using Microsoft.ApplicationInsights.AspNetCore.Extensions;
|
||||
using Microsoft.ApplicationInsights.Channel;
|
||||
using Microsoft.ApplicationInsights.Extensibility;
|
||||
#if NET451 || NET46
|
||||
using Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector.QuickPulse;
|
||||
using Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel;
|
||||
#if NET451 || NET46
|
||||
using Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector.QuickPulse;
|
||||
#endif
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
|
@ -99,9 +99,9 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
|
||||
private void AddTelemetryChannelAndProcessors(TelemetryConfiguration configuration)
|
||||
{
|
||||
#if NET451 || NET46
|
||||
configuration.TelemetryChannel = this.telemetryChannel ?? new ServerTelemetryChannel();
|
||||
|
||||
#if NET451 || NET46
|
||||
if (configuration.TelemetryChannel is ServerTelemetryChannel)
|
||||
{
|
||||
// Enabling Quick Pulse Metric Stream
|
||||
|
@ -120,6 +120,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (this.applicationInsightsServiceOptions.EnableAdaptiveSampling)
|
||||
{
|
||||
configuration.TelemetryProcessorChainBuilder.UseAdaptiveSampling();
|
||||
|
|
|
@ -65,14 +65,14 @@
|
|||
<PackageReference Include="System.Threading.Tasks.Analyzers" Version="1.2.0-beta2">
|
||||
<PrivateAssets>All</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.ApplicationInsights" Version="2.5.0-beta1-build13120" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.5.0-beta1-build01033" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel" Version="2.5.0-beta1-build13120" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights" Version="2.5.0-beta1-build19420" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.5.0-beta1-build07359" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel" Version="2.5.0-beta1-build19420" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net451' OR '$(TargetFramework)' == 'net46' ">
|
||||
<PackageReference Include="System.Net.Http" Version="4.3.1" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.PerfCounterCollector" Version="2.5.0-beta1-build01033" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.PerfCounterCollector" Version="2.5.0-beta1-build07359" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<VersionPrefix>1.0.2</VersionPrefix>
|
||||
<TargetFrameworks>net461;netstandard2.0</TargetFrameworks>
|
||||
<DelaySign>true</DelaySign>
|
||||
<PreserveCompilationContext>true</PreserveCompilationContext>
|
||||
<AssemblyName>ApplicationInsightsTypes</AssemblyName>
|
||||
<AssemblyOriginatorKeyFile>../../keys/35MSSharedLib1024.snk</AssemblyOriginatorKeyFile>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
|
||||
<PackageId>ApplicationInsightsTypes</PackageId>
|
||||
<NetStandardImplicitPackageVersion>2.0.0</NetStandardImplicitPackageVersion>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\test\$(MSBuildProjectName)</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Bond.Core.CSharp" Version="6.0.0" />
|
||||
<PackageReference Include="Bond.CSharp" Version="6.0.0" />
|
||||
<PackageReference Include="NETStandard.Library" Version="2.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net461' ">
|
||||
<Reference Include="System" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<BondCodegen Include="..\..\Schema\PublicSchema\AvailabilityData.bond">
|
||||
<Link>StackFrame.bond</Link>
|
||||
</BondCodegen>
|
||||
<BondCodegen Include="..\..\Schema\PublicSchema\Base.bond">
|
||||
<Link>Base.bond</Link>
|
||||
</BondCodegen>
|
||||
<BondCodegen Include="..\..\Schema\PublicSchema\ContextTagKeys.bond">
|
||||
<Link>ContextTagKeys.bond</Link>
|
||||
</BondCodegen>
|
||||
<BondCodegen Include="..\..\Schema\PublicSchema\Data.bond">
|
||||
<Link>Data.bond</Link>
|
||||
</BondCodegen>
|
||||
<BondCodegen Include="..\..\Schema\PublicSchema\DataPoint.bond">
|
||||
<Link>DataPoint.bond</Link>
|
||||
</BondCodegen>
|
||||
<BondCodegen Include="..\..\Schema\PublicSchema\DataPointType.bond">
|
||||
<Link>DataPointType.bond</Link>
|
||||
</BondCodegen>
|
||||
<BondCodegen Include="..\..\Schema\PublicSchema\Domain.bond">
|
||||
<Link>Domain.bond</Link>
|
||||
</BondCodegen>
|
||||
<BondCodegen Include="..\..\Schema\PublicSchema\Envelope.bond">
|
||||
<Link>Envelope.bond</Link>
|
||||
</BondCodegen>
|
||||
<BondCodegen Include="..\..\Schema\PublicSchema\EventData.bond">
|
||||
<Link>EventData.bond</Link>
|
||||
</BondCodegen>
|
||||
<BondCodegen Include="..\..\Schema\PublicSchema\ExceptionData.bond">
|
||||
<Link>ExceptionData.bond</Link>
|
||||
</BondCodegen>
|
||||
<BondCodegen Include="..\..\Schema\PublicSchema\ExceptionDetails.bond">
|
||||
<Link>ExceptionDetails.bond</Link>
|
||||
</BondCodegen>
|
||||
<BondCodegen Include="..\..\Schema\PublicSchema\MessageData.bond">
|
||||
<Link>MessageData.bond</Link>
|
||||
</BondCodegen>
|
||||
<BondCodegen Include="..\..\Schema\PublicSchema\MetricData.bond">
|
||||
<Link>MetricData.bond</Link>
|
||||
</BondCodegen>
|
||||
<BondCodegen Include="..\..\Schema\PublicSchema\PageViewData.bond">
|
||||
<Link>PageViewData.bond</Link>
|
||||
</BondCodegen>
|
||||
<BondCodegen Include="..\..\Schema\PublicSchema\PageViewPerfData.bond">
|
||||
<Link>PageViewPerfData.bond</Link>
|
||||
</BondCodegen>
|
||||
<BondCodegen Include="..\..\Schema\PublicSchema\RemoteDependencyData.bond">
|
||||
<Link>RemoteDependencyData.bond</Link>
|
||||
</BondCodegen>
|
||||
<BondCodegen Include="..\..\Schema\PublicSchema\RequestData.bond">
|
||||
<Link>RequestData.bond</Link>
|
||||
</BondCodegen>
|
||||
<BondCodegen Include="..\..\Schema\PublicSchema\SeverityLevel.bond">
|
||||
<Link>SeverityLevel.bond</Link>
|
||||
</BondCodegen>
|
||||
<BondCodegen Include="..\..\Schema\PublicSchema\StackFrame.bond">
|
||||
<Link>StackFrame.bond</Link>
|
||||
</BondCodegen>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,21 @@
|
|||
namespace AI
|
||||
{
|
||||
public class ItemType
|
||||
{
|
||||
public const string Metric = "Microsoft.ApplicationInsights.Metric";
|
||||
|
||||
public const string Request = "Microsoft.ApplicationInsights.Request";
|
||||
|
||||
public const string Exception = "Microsoft.ApplicationInsights.Exception";
|
||||
|
||||
public const string Message = "Microsoft.ApplicationInsights.Message";
|
||||
|
||||
public const string Event = "Microsoft.ApplicationInsights.Event";
|
||||
|
||||
public const string PageView = "Microsoft.ApplicationInsights.PageView";
|
||||
|
||||
public const string PageViewPerformance = "Microsoft.ApplicationInsights.PageViewPerformance";
|
||||
|
||||
public const string RemoteDependency = "Microsoft.ApplicationInsights.RemoteDependency";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
namespace AI
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides access to a complete telemetry item.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The part B telemetry item type.</typeparam>
|
||||
public class TelemetryItem<T> : Envelope
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the telemetry data.
|
||||
/// </summary>
|
||||
public new Data<T> data { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
namespace AI
|
||||
{
|
||||
public enum TelemetryItemType
|
||||
{
|
||||
Event,
|
||||
Exception,
|
||||
Message,
|
||||
Metric,
|
||||
PageView,
|
||||
PageViewPerformance,
|
||||
RemoteDependency,
|
||||
Request,
|
||||
Availability
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<VersionPrefix>2.0.0</VersionPrefix>
|
||||
<TargetFrameworks>net461;netcoreapp2.0</TargetFrameworks>
|
||||
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
|
||||
<RuntimeIdentifier Condition=" '$(TargetFramework)' == 'net461' ">win7-x86</RuntimeIdentifier>
|
||||
<DelaySign>true</DelaySign>
|
||||
<PreserveCompilationContext>true</PreserveCompilationContext>
|
||||
|
@ -10,7 +10,7 @@
|
|||
<AssemblyOriginatorKeyFile>../../keys/35MSSharedLib1024.snk</AssemblyOriginatorKeyFile>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
|
||||
<PackageId>EmptyApp.FunctionalTests</PackageId>
|
||||
<PackageId>EmptyApp20.FunctionalTests</PackageId>
|
||||
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
|
||||
<RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.0' ">2.0.0</RuntimeFrameworkVersion>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\test\$(MSBuildProjectName)</OutputPath>
|
||||
|
@ -24,10 +24,10 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0-preview-20170106-08" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="2.0.0" />
|
||||
<PackageReference Include="xunit" Version="2.2.0" />
|
||||
<PackageReference Include="xunit" Version="2.2.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net461' ">
|
||||
|
@ -46,5 +46,4 @@
|
|||
<ItemGroup>
|
||||
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -2,10 +2,11 @@
|
|||
{
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using AI;
|
||||
using FunctionalTestUtils;
|
||||
using Microsoft.ApplicationInsights.DataContracts;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public class RequestTelemetryEmptyAppTests : TelemetryTestsBase
|
||||
{
|
||||
|
@ -60,18 +61,25 @@
|
|||
var task = httpClient.GetAsync(server.BaseHost + "/Mixed");
|
||||
task.Wait(TestTimeoutMs);
|
||||
}
|
||||
|
||||
var telemetries = server.Execute<Envelope>(() => server.Listener.ReceiveItems(5, TestListenerTimeoutInMs));
|
||||
Assert.True(telemetries.Length >= 5);
|
||||
|
||||
Assert.Contains(telemetries.OfType<TelemetryItem<RemoteDependencyData>>(),
|
||||
t => ((TelemetryItem<RemoteDependencyData>)t).data.baseData.name == "GET /Mixed");
|
||||
|
||||
Assert.Contains(telemetries.OfType<TelemetryItem<RequestData>>(),
|
||||
t => ((TelemetryItem<RequestData>)t).data.baseData.name == "GET /Mixed");
|
||||
|
||||
Assert.Contains(telemetries.OfType<TelemetryItem<EventData>>(),
|
||||
t => ((TelemetryItem<EventData>)t).data.baseData.name == "GetContact");
|
||||
|
||||
Assert.Contains(telemetries.OfType<TelemetryItem<MetricData>>(),
|
||||
t => ((TelemetryItem<MetricData>)t).data.baseData.metrics[0].name == "ContactFile" && ((TelemetryItem<MetricData>)t).data.baseData.metrics[0].value == 1);
|
||||
|
||||
Assert.Contains(telemetries.OfType<TelemetryItem<MessageData>>(),
|
||||
t => ((TelemetryItem<MessageData>)t).data.baseData.message == "Fetched contact details." && ((TelemetryItem<MessageData>)t).data.baseData.severityLevel == AI.SeverityLevel.Information);
|
||||
}
|
||||
|
||||
var telemetries = server.BackChannel.Buffer;
|
||||
Assert.Contains(telemetries.OfType<DependencyTelemetry>(), t => t.Name == "GET /Mixed");
|
||||
Assert.True(telemetries.Count >= 4);
|
||||
Assert.Contains(telemetries.OfType<RequestTelemetry>(), t => t.Name == "GET /Mixed");
|
||||
Assert.Contains(telemetries.OfType<EventTelemetry>(), t => t.Name == "GetContact");
|
||||
Assert.Contains(telemetries.OfType<MetricTelemetry>(),
|
||||
t => t.Name == "ContactFile" && t.Value == 1);
|
||||
|
||||
Assert.Contains(telemetries.OfType<TraceTelemetry>(),
|
||||
t => t.Message == "Fetched contact details." && t.SeverityLevel == SeverityLevel.Information);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
namespace EmptyApp20.FunctionalTests.FunctionalTest
|
||||
{
|
||||
using FunctionalTestUtils;
|
||||
using Microsoft.ApplicationInsights.DataContracts;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
|
@ -16,7 +17,18 @@
|
|||
[Fact]
|
||||
public void TestBasicDependencyPropertiesAfterRequestingBasicPage()
|
||||
{
|
||||
this.ValidateBasicDependency(assemblyName, "/");
|
||||
const string RequestPath = "/";
|
||||
|
||||
using (var server = new InProcessServer(assemblyName))
|
||||
{
|
||||
DependencyTelemetry expected = new DependencyTelemetry();
|
||||
expected.ResultCode = "200";
|
||||
expected.Success = true;
|
||||
expected.Name = "GET /";
|
||||
expected.Data = server.BaseHost + RequestPath;
|
||||
|
||||
this.ValidateBasicDependency(server, RequestPath, expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
@ -7,19 +7,17 @@
|
|||
using Microsoft.ApplicationInsights.AspNetCore.Extensions;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.ApplicationInsights.Channel;
|
||||
using FunctionalTestUtils;
|
||||
using Microsoft.ApplicationInsights;
|
||||
using Microsoft.ApplicationInsights.DataContracts;
|
||||
using Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel;
|
||||
|
||||
public class Startup
|
||||
{
|
||||
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<ITelemetryChannel>(new BackTelemetryChannel());
|
||||
|
||||
var builder = new ConfigurationBuilder();
|
||||
builder.AddApplicationInsightsSettings(instrumentationKey: "Foo");
|
||||
builder.AddApplicationInsightsSettings(instrumentationKey: "Foo", endpointAddress: "http://localhost:4001/v2/track/", developerMode: true);
|
||||
services.AddApplicationInsightsTelemetry(builder.Build());
|
||||
}
|
||||
|
||||
|
|
|
@ -16,12 +16,14 @@
|
|||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Microsoft.ApplicationInsights.AspNetCore\Microsoft.ApplicationInsights.AspNetCore.csproj" />
|
||||
<ProjectReference Include="..\ApplicationInsightsTypes\ApplicationInsightsTypes.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.0.0" />
|
||||
<PackageReference Include="NETStandard.Library" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.0.0" />
|
||||
<PackageReference Include="NETStandard.Library" Version="2.0.0" />
|
||||
<PackageReference Include="System.Reactive.Linq" Version="3.1.1" />
|
||||
<PackageReference Include="xunit" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore" Version="2.0.0" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
namespace FunctionalTestUtils
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Threading.Tasks;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public abstract class HttpListenerObservableBase<T> : IObservable<T>, IDisposable
|
||||
{
|
||||
private readonly HttpListener listener;
|
||||
private IObservable<T> stream;
|
||||
|
||||
public HttpListenerObservableBase(string url)
|
||||
{
|
||||
this.listener = new HttpListener();
|
||||
this.listener.Prefixes.Add(url);
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
OnStart();
|
||||
if (this.stream != null)
|
||||
{
|
||||
this.Stop();
|
||||
}
|
||||
|
||||
if (!this.listener.IsListening)
|
||||
{
|
||||
this.listener.Start();
|
||||
}
|
||||
|
||||
this.stream = this.CreateStream();
|
||||
}
|
||||
|
||||
protected virtual void OnStart()
|
||||
{ }
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
this.Dispose();
|
||||
}
|
||||
|
||||
public IDisposable Subscribe(IObserver<T> observer)
|
||||
{
|
||||
if (this.stream == null)
|
||||
{
|
||||
throw new InvalidOperationException("Call HttpListenerObservable.Start before subscribing to the stream");
|
||||
}
|
||||
|
||||
return this.stream
|
||||
.Subscribe(observer);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (listener != null && listener.IsListening)
|
||||
{
|
||||
listener.Stop();
|
||||
listener.Close();
|
||||
this.stream = null;
|
||||
}
|
||||
}
|
||||
|
||||
private IObservable<T> CreateStream()
|
||||
{
|
||||
return Observable
|
||||
.Create<T>
|
||||
(obs =>
|
||||
Task.Factory.FromAsync(
|
||||
(a, c) => this.listener.BeginGetContext(a, c),
|
||||
ar => this.listener.EndGetContext(ar),
|
||||
null)
|
||||
.ToObservable()
|
||||
.SelectMany(this.CreateNewItemsFromContext)
|
||||
.Subscribe(obs)
|
||||
)
|
||||
.Repeat()
|
||||
.Publish()
|
||||
.RefCount();
|
||||
}
|
||||
|
||||
protected abstract IEnumerable<T> CreateNewItemsFromContext(HttpListenerContext context);
|
||||
}
|
||||
}
|
|
@ -2,14 +2,16 @@
|
|||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.ApplicationInsights.Channel;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using AI;
|
||||
|
||||
// a variant of aspnet/Hosting/test/Microsoft.AspNetCore.Hosting.Tests/HostingEngineTests.cs
|
||||
public class InProcessServer : IDisposable
|
||||
{
|
||||
private const string httpListenerConnectionString = "http://localhost:4001/v2/track/";
|
||||
|
||||
private static Random random = new Random();
|
||||
private static object noParallelism = new object();
|
||||
|
||||
public static Func<IWebHostBuilder, IWebHostBuilder> UseApplicationInsights =
|
||||
builder => builder.UseApplicationInsights();
|
||||
|
@ -18,22 +20,25 @@
|
|||
private IWebHost hostingEngine;
|
||||
private string url;
|
||||
|
||||
private readonly BackTelemetryChannel backChannel;
|
||||
|
||||
public BackTelemetryChannel BackChannel
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.backChannel;
|
||||
}
|
||||
}
|
||||
private TelemetryHttpListenerObservable listener;
|
||||
|
||||
|
||||
public InProcessServer(string assemblyName, Func<IWebHostBuilder, IWebHostBuilder> configureHost = null)
|
||||
{
|
||||
this.configureHost = configureHost;
|
||||
|
||||
var machineName = Environment.GetEnvironmentVariable("COMPUTERNAME");
|
||||
this.url = "http://" + machineName + ":" + random.Next(5000, 14000).ToString();
|
||||
this.backChannel = this.Start(assemblyName);
|
||||
this.url = "http://" + machineName + ":" + random.Next(5000, 14000).ToString();
|
||||
|
||||
this.Start(assemblyName);
|
||||
}
|
||||
|
||||
public TelemetryHttpListenerObservable Listener
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.listener;
|
||||
}
|
||||
}
|
||||
|
||||
public string BaseHost
|
||||
|
@ -44,9 +49,35 @@
|
|||
}
|
||||
}
|
||||
|
||||
public T[] Execute<T>(Func<T[]> receiveItemsMethod)
|
||||
{
|
||||
lock (noParallelism)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.listener = new TelemetryHttpListenerObservable(httpListenerConnectionString);
|
||||
this.listener.Start();
|
||||
|
||||
if (receiveItemsMethod != null)
|
||||
{
|
||||
return receiveItemsMethod();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (this.listener != null)
|
||||
{
|
||||
this.listener.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public IServiceProvider ApplicationServices { get; private set; }
|
||||
|
||||
private BackTelemetryChannel Start(string assemblyName)
|
||||
private void Start(string assemblyName)
|
||||
{
|
||||
var builder = new WebHostBuilder()
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
|
@ -64,7 +95,6 @@
|
|||
this.hostingEngine.Start();
|
||||
|
||||
this.ApplicationServices = this.hostingEngine.Services;
|
||||
return (BackTelemetryChannel)this.hostingEngine.Services.GetService<ITelemetryChannel>();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="TelemetryExtensions.cs" company="Microsoft Corporation">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
namespace FunctionalTestUtils
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
using AI;
|
||||
|
||||
public static class TelemetryExtensions
|
||||
{
|
||||
public static Envelope[] ReceiveItems(
|
||||
this TelemetryHttpListenerObservable listener,
|
||||
int timeOut)
|
||||
{
|
||||
if (null == listener)
|
||||
{
|
||||
throw new ArgumentNullException("listener");
|
||||
}
|
||||
|
||||
var result = listener
|
||||
.TakeUntil(DateTimeOffset.UtcNow.AddMilliseconds(timeOut))
|
||||
.ToEnumerable()
|
||||
.ToArray();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Envelope[] ReceiveItems(
|
||||
this TelemetryHttpListenerObservable listener,
|
||||
int count,
|
||||
int timeOut)
|
||||
{
|
||||
if (null == listener)
|
||||
{
|
||||
throw new ArgumentNullException("listener");
|
||||
}
|
||||
|
||||
var result = listener
|
||||
.TakeUntil(DateTimeOffset.UtcNow.AddMilliseconds(timeOut))
|
||||
.Take(count)
|
||||
.ToEnumerable()
|
||||
.ToArray();
|
||||
|
||||
if (result.Length != count)
|
||||
{
|
||||
throw new InvalidDataException("Incorrect number of items. Expected: " + count + " Received: " + result.Length);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static T[] ReceiveItemsOfType<T>(
|
||||
this TelemetryHttpListenerObservable listener,
|
||||
int timeOut)
|
||||
{
|
||||
var result = listener
|
||||
.Where(item => (item is TelemetryItem<T>))
|
||||
.Select(item => ((TelemetryItem<T>)item).data.baseData)
|
||||
.TakeUntil(DateTimeOffset.UtcNow.AddMilliseconds(timeOut))
|
||||
.ToEnumerable()
|
||||
.ToArray();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static T[] ReceiveItemsOfType<T>(
|
||||
this TelemetryHttpListenerObservable listener,
|
||||
int count,
|
||||
int timeOut)
|
||||
{
|
||||
var result = listener
|
||||
.Where(item => (item is TelemetryItem<T>))
|
||||
.Select(item => ((TelemetryItem<T>)item).data.baseData)
|
||||
.TakeUntil(DateTimeOffset.UtcNow.AddMilliseconds(timeOut))
|
||||
.Take(count)
|
||||
.ToEnumerable()
|
||||
.ToArray();
|
||||
|
||||
if (result.Length != count)
|
||||
{
|
||||
throw new InvalidDataException("Incorrect number of items. Expected: " + count + " Received: " + result.Length);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
namespace FunctionalTestUtils
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AI;
|
||||
|
||||
public class TelemetryHttpListenerObservable : HttpListenerObservableBase<Envelope>
|
||||
{
|
||||
public bool FailureDetected { get; set; }
|
||||
|
||||
public TelemetryHttpListenerObservable(string url) : base(url)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<Envelope> CreateNewItemsFromContext(HttpListenerContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
var request = context.Request;
|
||||
|
||||
string content = string.Empty;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.Headers["Content-Encoding"]) &&
|
||||
string.Equals("gzip", request.Headers["Content-Encoding"],
|
||||
StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
content = Decompress(request);
|
||||
}
|
||||
|
||||
Trace.WriteLine("=>");
|
||||
Trace.WriteLine("Item received: " + content);
|
||||
Trace.WriteLine("<=");
|
||||
|
||||
return TelemetryItemFactory.GetTelemetryItems(content);
|
||||
}
|
||||
finally
|
||||
{
|
||||
context.Response.Close();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decompresses content in gzip and returns decompressed string
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <returns></returns>
|
||||
private static string Decompress(HttpListenerRequest request)
|
||||
{
|
||||
var gzipStream = new GZipStream(request.InputStream, CompressionMode.Decompress);
|
||||
using (var streamReader = new StreamReader(gzipStream, request.ContentEncoding))
|
||||
{
|
||||
return streamReader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
namespace FunctionalTestUtils
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using AI;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
internal static class TelemetryItemFactory
|
||||
{
|
||||
public static IList<Envelope> GetTelemetryItems(string content)
|
||||
{
|
||||
var items = new List<Envelope>();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(content))
|
||||
{
|
||||
return items;
|
||||
}
|
||||
|
||||
var newLines = new [] { "\r\n", "\n" };
|
||||
|
||||
string[] lines = content.Split(newLines, StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (string line in lines)
|
||||
{
|
||||
JsonReader reader = new JsonTextReader(new StringReader(line));
|
||||
reader.DateParseHandling = DateParseHandling.None;
|
||||
JObject obj = JObject.Load(reader);
|
||||
var envelope = obj.ToObject<Envelope>();
|
||||
|
||||
var item = CreateTelemetryItem(envelope, line);
|
||||
items.Add(item);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
private static Envelope CreateTelemetryItem(
|
||||
Envelope envelope,
|
||||
string content)
|
||||
{
|
||||
Envelope result;
|
||||
|
||||
TelemetryItemType type;
|
||||
if (Enum.TryParse<TelemetryItemType>(envelope.data.baseType.Replace("Data", ""), out type))
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case TelemetryItemType.Exception:
|
||||
{
|
||||
result = JsonConvert.DeserializeObject<TelemetryItem<ExceptionData>>(content);
|
||||
break;
|
||||
}
|
||||
|
||||
case TelemetryItemType.Request:
|
||||
{
|
||||
result = JsonConvert.DeserializeObject<TelemetryItem<RequestData>>(content);
|
||||
break;
|
||||
}
|
||||
|
||||
case TelemetryItemType.Metric:
|
||||
{
|
||||
result = JsonConvert.DeserializeObject<TelemetryItem<MetricData>>(content);
|
||||
break;
|
||||
}
|
||||
|
||||
case TelemetryItemType.RemoteDependency:
|
||||
{
|
||||
result = JsonConvert.DeserializeObject<TelemetryItem<RemoteDependencyData>>(content);
|
||||
break;
|
||||
}
|
||||
|
||||
case TelemetryItemType.Message:
|
||||
{
|
||||
result = JsonConvert.DeserializeObject<TelemetryItem<MessageData>>(content);
|
||||
break;
|
||||
}
|
||||
|
||||
case TelemetryItemType.Event:
|
||||
{
|
||||
result = JsonConvert.DeserializeObject<TelemetryItem<EventData>>(content);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
throw new InvalidDataException("Unsupported telemetry type");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidDataException("Unsupported telemetry type");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,13 +2,13 @@
|
|||
{
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AI;
|
||||
using Microsoft.ApplicationInsights.DataContracts;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.ApplicationInsights.Channel;
|
||||
|
@ -16,18 +16,16 @@
|
|||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
#if NET451 || NET461
|
||||
using System.Net;
|
||||
using Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector;
|
||||
using Microsoft.ApplicationInsights.Extensibility;
|
||||
#endif
|
||||
|
||||
public abstract class TelemetryTestsBase
|
||||
{
|
||||
public const int TestListenerTimeoutInMs = 5000;
|
||||
protected const int TestTimeoutMs = 10000;
|
||||
private object noParallelism = new object();
|
||||
|
||||
protected readonly ITestOutputHelper output;
|
||||
|
||||
|
||||
public TelemetryTestsBase(ITestOutputHelper output)
|
||||
{
|
||||
this.output = output;
|
||||
|
@ -36,41 +34,31 @@
|
|||
[MethodImpl(MethodImplOptions.NoOptimization)]
|
||||
public void ValidateBasicRequest(InProcessServer server, string requestPath, RequestTelemetry expected)
|
||||
{
|
||||
lock (noParallelism)
|
||||
// Subtract 50 milliseconds to hack around strange behavior on build server where the RequestTelemetry.Timestamp is somehow sometimes earlier than now by a few milliseconds.
|
||||
expected.Timestamp = DateTimeOffset.Now.Subtract(TimeSpan.FromMilliseconds(50));
|
||||
Stopwatch timer = Stopwatch.StartNew();
|
||||
|
||||
var httpClientHandler = new HttpClientHandler();
|
||||
httpClientHandler.UseDefaultCredentials = true;
|
||||
|
||||
Task<HttpResponseMessage> task;
|
||||
using (HttpClient httpClient = new HttpClient(httpClientHandler, true))
|
||||
{
|
||||
// Subtract 50 milliseconds to hack around strange behavior on build server where the RequestTelemetry.Timestamp is somehow sometimes earlier than now by a few milliseconds.
|
||||
expected.Timestamp = DateTimeOffset.Now.Subtract(TimeSpan.FromMilliseconds(50));
|
||||
server.BackChannel.Buffer.Clear();
|
||||
Stopwatch timer = Stopwatch.StartNew();
|
||||
|
||||
var httpClientHandler = new HttpClientHandler();
|
||||
httpClientHandler.UseDefaultCredentials = true;
|
||||
|
||||
Task<HttpResponseMessage> task;
|
||||
using (HttpClient httpClient = new HttpClient(httpClientHandler, true))
|
||||
{
|
||||
task = httpClient.GetAsync(server.BaseHost + requestPath);
|
||||
task.Wait(TestTimeoutMs);
|
||||
}
|
||||
|
||||
timer.Stop();
|
||||
server.Dispose();
|
||||
|
||||
PrintBufferInfo(server.BackChannel.Buffer);
|
||||
|
||||
RequestTelemetry actual = server.BackChannel.Buffer.OfType<RequestTelemetry>().Where(t => t.Name == expected.Name).Single();
|
||||
server.BackChannel.Buffer.Clear();
|
||||
|
||||
Assert.Equal(expected.ResponseCode, actual.ResponseCode);
|
||||
Assert.Equal(expected.Name, actual.Name);
|
||||
Assert.Equal(expected.Success, actual.Success);
|
||||
Assert.Equal(expected.Url, actual.Url);
|
||||
InRange(actual.Timestamp, expected.Timestamp, DateTimeOffset.Now);
|
||||
output.WriteLine("actual.Timestamp: " + actual.Timestamp);
|
||||
output.WriteLine("actual.Duration: " + actual.Duration);
|
||||
output.WriteLine("timer.Elapsed: " + timer.Elapsed);
|
||||
Assert.True(actual.Duration < timer.Elapsed.Add(TimeSpan.FromMilliseconds(20)), "duration");
|
||||
task = httpClient.GetAsync(server.BaseHost + requestPath);
|
||||
task.Wait(TestTimeoutMs);
|
||||
}
|
||||
|
||||
timer.Stop();
|
||||
|
||||
var actual = server.Execute<RequestData>(() => server.Listener.ReceiveItemsOfType<RequestData>(1, TestListenerTimeoutInMs))[0];
|
||||
|
||||
Assert.Equal(expected.ResponseCode, actual.responseCode);
|
||||
Assert.Equal(expected.Name, actual.name);
|
||||
Assert.Equal(expected.Success, actual.success);
|
||||
Assert.Equal(expected.Url, new Uri(actual.url));
|
||||
output.WriteLine("actual.Duration: " + actual.duration);
|
||||
output.WriteLine("timer.Elapsed: " + timer.Elapsed);
|
||||
Assert.True(TimeSpan.Parse(actual.duration) < timer.Elapsed.Add(TimeSpan.FromMilliseconds(20)), "duration");
|
||||
}
|
||||
|
||||
public void ValidateBasicException(InProcessServer server, string requestPath, ExceptionTelemetry expected)
|
||||
|
@ -85,53 +73,41 @@
|
|||
task.Wait(TestTimeoutMs);
|
||||
}
|
||||
var result = task.Result;
|
||||
server.Dispose();
|
||||
PrintBufferInfo(server.BackChannel.Buffer);
|
||||
var actual = server.BackChannel.Buffer.OfType<ExceptionTelemetry>().Single();
|
||||
|
||||
Assert.Equal(expected.Exception.GetType(), actual.Exception.GetType());
|
||||
Assert.NotEmpty(actual.Exception.StackTrace);
|
||||
Assert.NotEmpty(actual.Context.Operation.Name);
|
||||
Assert.NotEmpty(actual.Context.Operation.Id);
|
||||
var actual = server.Execute<ExceptionData>(() => server.Listener.ReceiveItemsOfType<ExceptionData>(1, TestListenerTimeoutInMs))[0];
|
||||
|
||||
Assert.Equal(expected.Exception.GetType().ToString(), actual.exceptions[0].typeName);
|
||||
Assert.NotEmpty(actual.exceptions[0].parsedStack);
|
||||
}
|
||||
|
||||
public void ValidateBasicDependency(string assemblyName, string requestPath, Func<IWebHostBuilder, IWebHostBuilder> configureHost = null)
|
||||
public void ValidateBasicDependency(InProcessServer server, string requestPath, DependencyTelemetry expected)
|
||||
{
|
||||
DependencyTelemetry expected = new DependencyTelemetry();
|
||||
expected.ResultCode = "200";
|
||||
expected.Success = true;
|
||||
expected.Name = "GET " + requestPath;
|
||||
var httpClientHandler = new HttpClientHandler();
|
||||
httpClientHandler.UseDefaultCredentials = true;
|
||||
|
||||
InProcessServer server;
|
||||
using (server = new InProcessServer(assemblyName, configureHost))
|
||||
Task<HttpResponseMessage> task;
|
||||
using (var httpClient = new HttpClient(httpClientHandler, true))
|
||||
{
|
||||
expected.Data = server.BaseHost + requestPath;
|
||||
|
||||
var timer = Stopwatch.StartNew();
|
||||
Task<HttpResponseMessage> task;
|
||||
using (var httpClient = new HttpClient())
|
||||
{
|
||||
task = httpClient.GetAsync(server.BaseHost + requestPath);
|
||||
task.Wait(TestTimeoutMs);
|
||||
}
|
||||
var result = task.Result;
|
||||
timer.Stop();
|
||||
task = httpClient.GetAsync(server.BaseHost + requestPath);
|
||||
task.Wait(TestTimeoutMs);
|
||||
}
|
||||
var result = task.Result;
|
||||
|
||||
PrintBufferInfo(server.BackChannel.Buffer);
|
||||
IEnumerable<DependencyTelemetry> dependencies = server.BackChannel.Buffer.OfType<DependencyTelemetry>();
|
||||
Assert.NotNull(dependencies);
|
||||
Assert.NotEmpty(dependencies);
|
||||
var actual = server.Execute<Envelope>(() => server.Listener.ReceiveItems(2, TestListenerTimeoutInMs));
|
||||
|
||||
var dependencyTelemetry = dependencies.FirstOrDefault(d => d.Name == expected.Name
|
||||
&& d.Data == expected.Data
|
||||
&& d.Success == expected.Success
|
||||
&& d.ResultCode == expected.ResultCode);
|
||||
var dependencyTelemetry = actual.OfType<TelemetryItem<RemoteDependencyData>>().FirstOrDefault();
|
||||
Assert.NotNull(dependencyTelemetry);
|
||||
var dependencyData = ((TelemetryItem<RemoteDependencyData>)dependencyTelemetry).data.baseData;
|
||||
Assert.Equal(expected.Data, dependencyData.data);
|
||||
Assert.Equal(expected.ResultCode, dependencyData.resultCode);
|
||||
Assert.Equal(expected.Success, dependencyData.success);
|
||||
|
||||
#if !NET461
|
||||
var requestTelemetry = server.BackChannel.Buffer.OfType<RequestTelemetry>().Single();
|
||||
Assert.Equal(requestTelemetry.Context.Operation.ParentId, dependencyTelemetry.Id);
|
||||
var requestTelemetry = actual.OfType<TelemetryItem<RequestData>>().FirstOrDefault();
|
||||
Assert.NotNull(requestTelemetry);
|
||||
|
||||
Assert.Contains(dependencyTelemetry.tags["ai.operation.id"], requestTelemetry.tags["ai.operation.parentId"]);
|
||||
Assert.Equal(requestTelemetry.tags["ai.operation.id"], dependencyTelemetry.tags["ai.operation.id"]);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -147,38 +123,10 @@
|
|||
var timer = timerField.GetValue(perfModule);
|
||||
timerField.FieldType.InvokeMember("ScheduleNextTick", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance, null, timer, new object[] { TimeSpan.FromMilliseconds(10) });
|
||||
|
||||
DateTime timeout = DateTime.UtcNow.AddMilliseconds(TestTimeoutMs);
|
||||
int numberOfCountersSent = 0;
|
||||
do
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
numberOfCountersSent += server.BackChannel.Buffer.OfType<MetricTelemetry>().Distinct().Count();
|
||||
} while (numberOfCountersSent == 0 && DateTime.UtcNow < timeout);
|
||||
|
||||
Assert.True(numberOfCountersSent > 0);
|
||||
var actual = server.Execute<Envelope>(() => server.Listener.ReceiveItems(TestListenerTimeoutInMs));
|
||||
Assert.True(actual.Length > 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Tests if a DateTimeOffset is in a specified range and prints a more detailed error message if it is not.
|
||||
/// </summary>
|
||||
/// <param name="actual">The actual value to test.</param>
|
||||
/// <param name="low">The minimum of the range.</param>
|
||||
/// <param name="high">The maximum of the range.</param>
|
||||
private void InRange(DateTimeOffset actual, DateTimeOffset low, DateTimeOffset high)
|
||||
{
|
||||
string dateFormat = "yyyy-MM-dd HH:mm:ss.ffffzzz";
|
||||
Assert.True(low <= actual && actual <= high, $"Range: ({low.ToString(dateFormat)} - {high.ToString(dateFormat)})\nActual: {actual.ToString(dateFormat)}");
|
||||
}
|
||||
|
||||
private void PrintBufferInfo(IList<ITelemetry> buffer)
|
||||
{
|
||||
output.WriteLine(string.Format("Backchannel buffer item count: {0} ", buffer.Count));
|
||||
foreach (var bufferItem in buffer)
|
||||
{
|
||||
output.WriteLine(string.Format("Backchannel item: {0}", bufferItem.GetType()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using AI;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
|
@ -21,24 +22,25 @@
|
|||
public void CorrelationInfoIsPropagatedToDependendedService()
|
||||
{
|
||||
#if netcoreapp2_0 // Correlation works on .Net core.
|
||||
InProcessServer server;
|
||||
|
||||
using (server = new InProcessServer(assemblyName, InProcessServer.UseApplicationInsights))
|
||||
using (var server = new InProcessServer(assemblyName, InProcessServer.UseApplicationInsights))
|
||||
{
|
||||
using (var httpClient = new HttpClient())
|
||||
{
|
||||
var task = httpClient.GetAsync(server.BaseHost + "/");
|
||||
task.Wait(TestTimeoutMs);
|
||||
}
|
||||
|
||||
var actual = server.Execute<Envelope>(() => server.Listener.ReceiveItems(2, TestListenerTimeoutInMs));
|
||||
|
||||
var dependencyTelemetry = actual.OfType<TelemetryItem<RemoteDependencyData>>().FirstOrDefault();
|
||||
Assert.NotNull(dependencyTelemetry);
|
||||
|
||||
var requestTelemetry = actual.OfType<TelemetryItem<RequestData>>().FirstOrDefault();
|
||||
Assert.NotNull(requestTelemetry);
|
||||
|
||||
Assert.Equal(requestTelemetry.tags["ai.operation.id"], dependencyTelemetry.tags["ai.operation.id"]);
|
||||
Assert.Contains(dependencyTelemetry.tags["ai.operation.id"], requestTelemetry.tags["ai.operation.parentId"]);
|
||||
}
|
||||
|
||||
var telemetries = server.BackChannel.Buffer;
|
||||
|
||||
Assert.True(telemetries.Count >= 2);
|
||||
var requestTelemetry = telemetries.OfType<RequestTelemetry>().Single();
|
||||
var dependencyTelemetry = telemetries.OfType<DependencyTelemetry>().Single();
|
||||
Assert.Equal(requestTelemetry.Context.Operation.Id, dependencyTelemetry.Context.Operation.Id);
|
||||
Assert.Equal(requestTelemetry.Context.Operation.ParentId, dependencyTelemetry.Id);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,16 @@
|
|||
using System.Diagnostics;
|
||||
|
||||
namespace MVCFramework20.FunctionalTests.FunctionalTest
|
||||
{
|
||||
namespace MVCFramework20.FunctionalTests.FunctionalTest
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
|
||||
using AI;
|
||||
using FunctionalTestUtils;
|
||||
using Microsoft.ApplicationInsights.Channel;
|
||||
using Microsoft.ApplicationInsights.DataContracts;
|
||||
using Xunit;
|
||||
using Microsoft.ApplicationInsights.Extensibility;
|
||||
using Microsoft.ApplicationInsights.DependencyCollector;
|
||||
using Microsoft.ApplicationInsights.Extensibility;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public class DependencyTelemetryMvcTests : TelemetryTestsBase
|
||||
|
@ -27,9 +24,7 @@ namespace MVCFramework20.FunctionalTests.FunctionalTest
|
|||
public void CorrelationInfoIsNotAddedToRequestHeaderIfUserAddDomainToExcludedList()
|
||||
{
|
||||
#if netcoreapp2_0 // Correlation is supported on .Net core.
|
||||
InProcessServer server;
|
||||
|
||||
using (server = new InProcessServer(assemblyName, InProcessServer.UseApplicationInsights))
|
||||
using (var server = new InProcessServer(assemblyName, InProcessServer.UseApplicationInsights))
|
||||
{
|
||||
var dependencyCollectorModule = server.ApplicationServices.GetServices<ITelemetryModule>().OfType<DependencyTrackingTelemetryModule>().Single();
|
||||
dependencyCollectorModule.ExcludeComponentCorrelationHttpHeadersOnDomains.Add(server.BaseHost);
|
||||
|
@ -39,20 +34,24 @@ namespace MVCFramework20.FunctionalTests.FunctionalTest
|
|||
var task = httpClient.GetAsync(server.BaseHost + "/");
|
||||
task.Wait(TestTimeoutMs);
|
||||
}
|
||||
}
|
||||
|
||||
var telemetries = server.BackChannel.Buffer;
|
||||
try
|
||||
{
|
||||
Assert.True(telemetries.Count >= 2);
|
||||
var requestTelemetry = telemetries.OfType<RequestTelemetry>().Single();
|
||||
var dependencyTelemetry = telemetries.OfType<DependencyTelemetry>().Single();
|
||||
Assert.NotEqual(requestTelemetry.Context.Operation.Id, dependencyTelemetry.Context.Operation.Id);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
string data = DebugTelemetryItems(telemetries);
|
||||
throw new Exception(data, e);
|
||||
var actual = server.Execute<Envelope>(() => server.Listener.ReceiveItems(TestListenerTimeoutInMs));
|
||||
|
||||
try
|
||||
{
|
||||
var dependencyTelemetry = actual.OfType<TelemetryItem<RemoteDependencyData>>().FirstOrDefault();
|
||||
Assert.NotNull(dependencyTelemetry);
|
||||
|
||||
var requestTelemetry = actual.OfType<TelemetryItem<RequestData>>().FirstOrDefault();
|
||||
Assert.NotNull(requestTelemetry);
|
||||
|
||||
Assert.NotEqual(requestTelemetry.tags["ai.operation.id"], dependencyTelemetry.tags["ai.operation.id"]);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
string data = DebugTelemetryItems(actual);
|
||||
throw new Exception(data, e);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -72,20 +71,25 @@ namespace MVCFramework20.FunctionalTests.FunctionalTest
|
|||
var task = httpClient.GetAsync(server.BaseHost + "/" + path);
|
||||
task.Wait(TestTimeoutMs);
|
||||
}
|
||||
}
|
||||
|
||||
var telemetries = server.BackChannel.Buffer;
|
||||
try
|
||||
{
|
||||
Assert.True(telemetries.Count >= 2);
|
||||
var requestTelemetry = telemetries.OfType<RequestTelemetry>().Single();
|
||||
var dependencyTelemetry = telemetries.OfType<DependencyTelemetry>().First(t => t.Name == "MyDependency");
|
||||
Assert.Equal(requestTelemetry.Context.Operation.Id, dependencyTelemetry.Context.Operation.Id);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
string data = DebugTelemetryItems(telemetries);
|
||||
throw new Exception(data, e);
|
||||
var actual = server.Execute<Envelope>(() => server.Listener.ReceiveItems(TestListenerTimeoutInMs));
|
||||
|
||||
try
|
||||
{
|
||||
var dependencyTelemetry = actual.OfType<TelemetryItem<RemoteDependencyData>>()
|
||||
.First( t => ((TelemetryItem<RemoteDependencyData>)t).data.baseData.name == "MyDependency");
|
||||
Assert.NotNull(dependencyTelemetry);
|
||||
|
||||
var requestTelemetry = actual.OfType<TelemetryItem<RequestData>>().FirstOrDefault();
|
||||
Assert.NotNull(requestTelemetry);
|
||||
|
||||
Assert.Equal(requestTelemetry.tags["ai.operation.id"], dependencyTelemetry.tags["ai.operation.id"]);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
string data = DebugTelemetryItems(actual);
|
||||
throw new Exception(data, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,34 +107,42 @@ namespace MVCFramework20.FunctionalTests.FunctionalTest
|
|||
var task = httpClient.GetAsync(server.BaseHost + "/" + path);
|
||||
task.Wait(TestTimeoutMs);
|
||||
}
|
||||
}
|
||||
|
||||
// Filter out any unexpected telemetry items.
|
||||
IEnumerable<ITelemetry> telemetries = server.BackChannel.Buffer.Where((t) => t.Context?.Operation?.Name != null && t.Context.Operation.Name.Contains(path));
|
||||
try
|
||||
{
|
||||
Assert.NotNull(telemetries);
|
||||
var requestTelemetry = telemetries.OfType<RequestTelemetry>().Single();
|
||||
var dependencyTelemetry = telemetries.First(t => t is DependencyTelemetry && (t as DependencyTelemetry).Name == "MyDependency");
|
||||
Assert.Equal(requestTelemetry.Id, dependencyTelemetry.Context.Operation.ParentId);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
string data = DebugTelemetryItems(server.BackChannel.Buffer);
|
||||
throw new Exception(data, e);
|
||||
var actual = server.Execute<Envelope>(() => server.Listener.ReceiveItems(TestListenerTimeoutInMs));
|
||||
|
||||
try
|
||||
{
|
||||
var dependencyTelemetry = actual.OfType<TelemetryItem<RemoteDependencyData>>()
|
||||
.First(t => ((TelemetryItem<RemoteDependencyData>)t).data.baseData.name == "MyDependency");
|
||||
Assert.NotNull(dependencyTelemetry);
|
||||
|
||||
var requestTelemetry = actual.OfType<TelemetryItem<RequestData>>().FirstOrDefault();
|
||||
Assert.NotNull(requestTelemetry);
|
||||
|
||||
Assert.Contains(requestTelemetry.tags["ai.operation.id"], dependencyTelemetry.tags["ai.operation.parentId"]);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
string data = DebugTelemetryItems(actual);
|
||||
throw new Exception(data, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string DebugTelemetryItems(IList<ITelemetry> telemetries)
|
||||
private string DebugTelemetryItems(Envelope[] telemetries)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
foreach (ITelemetry telemetry in telemetries)
|
||||
foreach (Envelope telemetry in telemetries)
|
||||
{
|
||||
DependencyTelemetry dependency = telemetry as DependencyTelemetry;
|
||||
if (dependency != null) {
|
||||
builder.AppendLine($"{dependency.ToString()} - {dependency.Data} - {dependency.Duration} - {dependency.Id} - {dependency.Name} - {dependency.ResultCode} - {dependency.Sequence} - {dependency.Success} - {dependency.Target} - {dependency.Type}");
|
||||
} else {
|
||||
builder.AppendLine($"{telemetry.ToString()} - {telemetry.Context?.Operation?.Name}");
|
||||
TelemetryItem<RemoteDependencyData> dependency = telemetry as TelemetryItem<RemoteDependencyData>;
|
||||
if (dependency != null)
|
||||
{
|
||||
var data = ((TelemetryItem<RemoteDependencyData>)dependency).data.baseData;
|
||||
builder.AppendLine($"{dependency.ToString()} - {data.data} - {data.duration} - {data.id} - {data.name} - {data.resultCode} - {data.success} - {data.target} - {data.type}");
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AppendLine($"{telemetry.ToString()} - {telemetry.name}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MVCFramework20.FunctionalTests.FunctionalTest
|
||||
namespace MVCFramework20.FunctionalTests.FunctionalTest
|
||||
{
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
|
||||
using AI;
|
||||
using FunctionalTestUtils;
|
||||
using Microsoft.ApplicationInsights.DataContracts;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
|
||||
public class RequestTelemetryMvcTests : TelemetryTestsBase
|
||||
{
|
||||
private const string assemblyName = "MVCFramework20.FunctionalTests";
|
||||
|
@ -80,17 +79,25 @@ namespace MVCFramework20.FunctionalTests.FunctionalTest
|
|||
var task = httpClient.GetAsync(server.BaseHost + "/Home/Contact");
|
||||
task.Wait(TestTimeoutMs);
|
||||
}
|
||||
}
|
||||
var telemetries = server.BackChannel.Buffer;
|
||||
Assert.Contains(telemetries.OfType<DependencyTelemetry>(), t => t.Name == "GET /Home/Contact");
|
||||
Assert.True(telemetries.Count >= 4);
|
||||
Assert.Contains(telemetries.OfType<RequestTelemetry>(), t => t.Name == "GET Home/Contact");
|
||||
Assert.Contains(telemetries.OfType<EventTelemetry>(), t => t.Name == "GetContact");
|
||||
Assert.Contains(telemetries.OfType<MetricTelemetry>(),
|
||||
t => t.Name == "ContactFile" && t.Value == 1);
|
||||
|
||||
Assert.Contains(telemetries.OfType<TraceTelemetry>(),
|
||||
t => t.Message == "Fetched contact details." && t.SeverityLevel == SeverityLevel.Information);
|
||||
var telemetries = server.Execute<Envelope>(() => server.Listener.ReceiveItems(5, TestListenerTimeoutInMs));
|
||||
Assert.True(telemetries.Length >= 5);
|
||||
|
||||
Assert.Contains(telemetries.OfType<TelemetryItem<RemoteDependencyData>>(),
|
||||
t => ((TelemetryItem<RemoteDependencyData>)t).data.baseData.name == "GET /Home/Contact");
|
||||
|
||||
Assert.Contains(telemetries.OfType<TelemetryItem<RequestData>>(),
|
||||
t => ((TelemetryItem<RequestData>)t).data.baseData.name == "GET Home/Contact");
|
||||
|
||||
Assert.Contains(telemetries.OfType<TelemetryItem<EventData>>(),
|
||||
t => ((TelemetryItem<EventData>)t).data.baseData.name == "GetContact");
|
||||
|
||||
Assert.Contains(telemetries.OfType<TelemetryItem<MetricData>>(),
|
||||
t => ((TelemetryItem<MetricData>)t).data.baseData.metrics[0].name == "ContactFile" && ((TelemetryItem<MetricData>)t).data.baseData.metrics[0].value == 1);
|
||||
|
||||
Assert.Contains(telemetries.OfType<TelemetryItem<MessageData>>(),
|
||||
t => ((TelemetryItem<MessageData>)t).data.baseData.message == "Fetched contact details." && ((TelemetryItem<MessageData>)t).data.baseData.severityLevel == AI.SeverityLevel.Information);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
namespace MVCFramework20.FunctionalTests.FunctionalTest
|
||||
{
|
||||
using FunctionalTestUtils;
|
||||
using Microsoft.ApplicationInsights.DataContracts;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
|
@ -17,7 +18,18 @@
|
|||
[Fact]
|
||||
public void TestBasicDependencyPropertiesAfterRequestingBasicPage()
|
||||
{
|
||||
this.ValidateBasicDependency(assemblyName, "/Home/About/5", InProcessServer.UseApplicationInsights);
|
||||
const string RequestPath = "/Home/About/5";
|
||||
|
||||
using (var server = new InProcessServer(assemblyName))
|
||||
{
|
||||
DependencyTelemetry expected = new DependencyTelemetry();
|
||||
expected.ResultCode = "200";
|
||||
expected.Success = true;
|
||||
expected.Name = "GET " + RequestPath;
|
||||
expected.Data = server.BaseHost + RequestPath;
|
||||
|
||||
this.ValidateBasicDependency(server, RequestPath, expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<VersionPrefix>2.0.0</VersionPrefix>
|
||||
<TargetFrameworks>net461;netcoreapp2.0</TargetFrameworks>
|
||||
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
|
||||
<RuntimeIdentifier Condition=" '$(TargetFramework)' == 'net461' ">win7-x86</RuntimeIdentifier>
|
||||
<DelaySign>true</DelaySign>
|
||||
<PreserveCompilationContext>true</PreserveCompilationContext>
|
||||
|
@ -43,8 +43,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0-preview-20170106-08" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="2.0.0" />
|
||||
|
@ -63,7 +62,8 @@
|
|||
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.0" />
|
||||
<PackageReference Include="xunit" Version="2.2.0" />
|
||||
<PackageReference Include="xunit" Version="2.2.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -23,7 +23,10 @@ namespace MVCFramework20.FunctionalTests
|
|||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<ITelemetryChannel>(new BackTelemetryChannel());
|
||||
var builder = new ConfigurationBuilder();
|
||||
builder.AddApplicationInsightsSettings(instrumentationKey: "Foo", endpointAddress: "http://localhost:4001/v2/track/", developerMode: true);
|
||||
|
||||
services.AddApplicationInsightsTelemetry(builder.Build());
|
||||
services.AddMvc();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
namespace WebApi20.FunctionalTests.FunctionalTest
|
||||
using Xunit;
|
||||
|
||||
[assembly: CollectionBehavior(DisableTestParallelization = true)]
|
||||
namespace WebApi20.FunctionalTests.FunctionalTest
|
||||
{
|
||||
using System;
|
||||
using FunctionalTestUtils;
|
||||
using Microsoft.ApplicationInsights.DataContracts;
|
||||
using Xunit;
|
||||
using Microsoft.ApplicationInsights.Extensibility;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public class ExceptionTelemetryWebApiTests : TelemetryTestsBase
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
using Xunit;
|
||||
|
||||
[assembly: CollectionBehavior(DisableTestParallelization = true)]
|
||||
namespace WebApi20.FunctionalTests.FunctionalTest
|
||||
namespace WebApi20.FunctionalTests.FunctionalTest
|
||||
{
|
||||
using FunctionalTestUtils;
|
||||
using Microsoft.ApplicationInsights.DataContracts;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public class TelemetryModuleWorkingWebApiTests : TelemetryTestsBase
|
||||
|
@ -18,7 +17,18 @@ namespace WebApi20.FunctionalTests.FunctionalTest
|
|||
[Fact]
|
||||
public void TestBasicDependencyPropertiesAfterRequestingBasicPage()
|
||||
{
|
||||
this.ValidateBasicDependency(assemblyName, "/api/values");
|
||||
const string RequestPath = "/api/values";
|
||||
|
||||
using (var server = new InProcessServer(assemblyName))
|
||||
{
|
||||
DependencyTelemetry expected = new DependencyTelemetry();
|
||||
expected.ResultCode = "200";
|
||||
expected.Success = true;
|
||||
expected.Name = "GET " + RequestPath;
|
||||
expected.Data = server.BaseHost + RequestPath;
|
||||
|
||||
this.ValidateBasicDependency(server, RequestPath, expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
@ -10,6 +10,7 @@ using Microsoft.Extensions.Logging;
|
|||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.ApplicationInsights.Channel;
|
||||
using FunctionalTestUtils;
|
||||
using System.IO;
|
||||
|
||||
namespace WebApi20.FunctionalTests
|
||||
{
|
||||
|
@ -25,8 +26,10 @@ namespace WebApi20.FunctionalTests
|
|||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<ITelemetryChannel>(new BackTelemetryChannel());
|
||||
services.AddApplicationInsightsTelemetry(Configuration);
|
||||
var builder = new ConfigurationBuilder();
|
||||
builder.AddApplicationInsightsSettings(instrumentationKey: "Foo", endpointAddress: "http://localhost:4001/v2/track/", developerMode: true);
|
||||
|
||||
services.AddApplicationInsightsTelemetry(builder.Build());
|
||||
services.AddMvc();
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<VersionPrefix>2.0.0</VersionPrefix>
|
||||
<TargetFrameworks>net461;netcoreapp2.0</TargetFrameworks>
|
||||
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
|
||||
<RuntimeIdentifier Condition=" '$(TargetFramework)' == 'net461' ">win7-x86</RuntimeIdentifier>
|
||||
<DelaySign>true</DelaySign>
|
||||
<PreserveCompilationContext>true</PreserveCompilationContext>
|
||||
|
@ -35,7 +35,6 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0-preview-20170106-08" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.WebApiCompatShim" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0" />
|
||||
|
@ -43,6 +42,7 @@
|
|||
<PackageReference Include="xunit" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.0.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
Загрузка…
Ссылка в новой задаче