From 1b274fb41f1d339890af98f0fb5bb60103f92239 Mon Sep 17 00:00:00 2001 From: Mark Wolff Date: Tue, 15 Sep 2020 16:07:31 -0700 Subject: [PATCH 01/13] codegen: use generated Envelope --- .../Contracts/Generated/Envelope.ts | 55 ------------------- .../Declarations/Contracts/Generated/index.ts | 1 - .../src/export/exporter.ts | 2 +- .../src/platform/nodejs/httpSender.ts | 2 +- .../src/types.ts | 2 +- .../src/utils/eventhub.ts | 20 ++++--- .../src/utils/spanUtils.ts | 24 ++++---- .../test/common/assert.ts | 29 ++++++---- .../test/common/scenario/basic.ts | 20 +++---- .../test/common/scenario/types.ts | 2 +- .../test/functional/trace.test.ts | 2 +- .../test/unit/export/export.test.ts | 31 +++++++---- .../unit/platform/nodejs/httpSender.test.ts | 7 ++- .../nodejs/persist/fileSystemPersist.test.ts | 8 ++- .../test/unit/utils/eventhub.test.ts | 31 ++++++----- .../test/unit/utils/spanUtils.test.ts | 19 ++++--- 16 files changed, 119 insertions(+), 136 deletions(-) delete mode 100644 sdk/monitor/monitor-opentelemetry-exporter/src/Declarations/Contracts/Generated/Envelope.ts diff --git a/sdk/monitor/monitor-opentelemetry-exporter/src/Declarations/Contracts/Generated/Envelope.ts b/sdk/monitor/monitor-opentelemetry-exporter/src/Declarations/Contracts/Generated/Envelope.ts deleted file mode 100644 index ec03cf3101bb..000000000000 --- a/sdk/monitor/monitor-opentelemetry-exporter/src/Declarations/Contracts/Generated/Envelope.ts +++ /dev/null @@ -1,55 +0,0 @@ -// THIS FILE WAS AUTOGENERATED -import Base = require("./Base"); -"use strict"; - -/** - * System variables for a telemetry item. - */ -class Envelope { - /** - * 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. - */ - public ver: number; - - /** - * Type name of telemetry data item. - */ - public name: string | undefined; - - /** - * 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. - */ - public time: string | undefined; - - /** - * Sampling rate used in application. This telemetry item represents 1 / sampleRate actual telemetry items. - */ - public sampleRate: number; - - /** - * Sequence field used to track absolute order of uploaded events. - */ - public seq: string | undefined; - - /** - * The application's instrumentation key. The key is typically represented as a GUID, but there are cases when it is not a guid. No code should rely on iKey being a GUID. Instrumentation key is case insensitive. - */ - public iKey: string | undefined; - - /** - * Key/value collection of context properties. See ContextTagKeys for information on available properties. - */ - public tags: any; - - /** - * Telemetry data item. - */ - public data: Base | undefined; - - constructor() { - this.ver = 1; - this.sampleRate = 100.0; - this.tags = {}; - } -} -export = Envelope; diff --git a/sdk/monitor/monitor-opentelemetry-exporter/src/Declarations/Contracts/Generated/index.ts b/sdk/monitor/monitor-opentelemetry-exporter/src/Declarations/Contracts/Generated/index.ts index b5f2bd14709e..5a7686fb0f9a 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/src/Declarations/Contracts/Generated/index.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/src/Declarations/Contracts/Generated/index.ts @@ -4,4 +4,3 @@ export import Base = require("./Base"); export import ContextTagKeys = require("./ContextTagKeys"); export import Data = require("./Data"); export import Domain = require("./Domain"); -export import Envelope = require("./Envelope"); diff --git a/sdk/monitor/monitor-opentelemetry-exporter/src/export/exporter.ts b/sdk/monitor/monitor-opentelemetry-exporter/src/export/exporter.ts index bf25a7341796..bea48953256e 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/src/export/exporter.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/src/export/exporter.ts @@ -3,13 +3,13 @@ import { Logger } from "@opentelemetry/api"; import { ConsoleLogger, LogLevel, ExportResult } from "@opentelemetry/core"; -import { Envelope } from "../Declarations/Contracts"; import { ConnectionStringParser } from "../utils/connectionStringParser"; import { HttpSender, FileSystemPersist } from "../platform"; import { DEFAULT_EXPORTER_CONFIG, AzureExporterConfig } from "../config"; import { BaseExporter, TelemetryProcessor, PersistentStorage, Sender } from "../types"; import { isRetriable, BreezeResponse } from "../utils/breezeUtils"; import { ENV_CONNECTION_STRING, ENV_INSTRUMENTATION_KEY } from "../Declarations/Constants"; +import { TelemetryItem as Envelope } from "../generated"; export abstract class AzureMonitorBaseExporter implements BaseExporter { protected readonly _persister: PersistentStorage; diff --git a/sdk/monitor/monitor-opentelemetry-exporter/src/platform/nodejs/httpSender.ts b/sdk/monitor/monitor-opentelemetry-exporter/src/platform/nodejs/httpSender.ts index c3e77e64a638..4db63063e570 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/src/platform/nodejs/httpSender.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/src/platform/nodejs/httpSender.ts @@ -5,7 +5,7 @@ import * as zlib from "zlib"; import { Logger } from "@opentelemetry/api"; import { ConsoleLogger, LogLevel } from "@opentelemetry/core"; import { Sender, SenderResult } from "../../types"; -import { Envelope } from "../../Declarations/Contracts"; +import { TelemetryItem as Envelope } from "../../generated"; import { DEFAULT_SENDER_OPTIONS, NodejsPlatformConfig } from "../types"; import { promisify } from "util"; import { DefaultHttpClient, HttpClient, HttpHeaders, WebResource } from "@azure/core-http"; diff --git a/sdk/monitor/monitor-opentelemetry-exporter/src/types.ts b/sdk/monitor/monitor-opentelemetry-exporter/src/types.ts index 60f912607320..c2afb7249b7c 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/src/types.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/src/types.ts @@ -2,7 +2,7 @@ // Licensed under the MIT license. import { ExportResult } from "@opentelemetry/core"; -import { Envelope } from "./Declarations/Contracts"; +import { TelemetryItem as Envelope } from "./generated"; export type Tags = { [key: string]: string }; export type PropertyType = string | number | boolean | object | Array; diff --git a/sdk/monitor/monitor-opentelemetry-exporter/src/utils/eventhub.ts b/sdk/monitor/monitor-opentelemetry-exporter/src/utils/eventhub.ts index 1872685a5c5c..23752d134671 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/src/utils/eventhub.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/src/utils/eventhub.ts @@ -5,7 +5,7 @@ import { SpanKind } from "@opentelemetry/api"; import { hrTimeToMilliseconds } from "@opentelemetry/core"; import { GeneralAttribute } from "@opentelemetry/semantic-conventions"; import { ReadableSpan } from "@opentelemetry/tracing"; -import { Envelope } from "../Declarations/Contracts"; +import { RemoteDependencyData, TelemetryItem as Envelope } from "../generated"; import { TIME_SINCE_ENQUEUED, ENQUEUED_TIME } from "./constants/applicationinsights"; import { AzNamespace, @@ -46,20 +46,22 @@ export const parseEventHubSpan = (span: ReadableSpan, envelope: Envelope): void "unknown") as string).replace(/\/$/g, ""); // remove trailing "/" const messageBusDestination = (span.attributes[MessageBusDestination] || "unknown") as string; + const baseData = envelope.data.baseData as RemoteDependencyData; + switch (span.kind) { case SpanKind.CLIENT: - envelope.data.baseData.type = namespace; - envelope.data.baseData.target = `${peerAddress}/${messageBusDestination}`; + baseData.type = namespace; + baseData.target = `${peerAddress}/${messageBusDestination}`; break; case SpanKind.PRODUCER: - envelope.data.baseData.type = `Queue Message | ${namespace}`; - envelope.data.baseData.target = `${peerAddress}/${messageBusDestination}`; + baseData.type = `Queue Message | ${namespace}`; + baseData.target = `${peerAddress}/${messageBusDestination}`; break; case SpanKind.CONSUMER: - envelope.data.baseData.type = `Queue Message | ${namespace}`; - envelope.data.baseData.source = `${peerAddress}/${messageBusDestination}`; - envelope.data.baseData.measurements = { - ...envelope.data.baseData.measurements, + baseData.type = `Queue Message | ${namespace}`; + (baseData as any).source = `${peerAddress}/${messageBusDestination}`; + baseData.measurements = { + ...baseData.measurements, [TIME_SINCE_ENQUEUED]: getTimeSinceEnqueued(span) }; break; diff --git a/sdk/monitor/monitor-opentelemetry-exporter/src/utils/spanUtils.ts b/sdk/monitor/monitor-opentelemetry-exporter/src/utils/spanUtils.ts index a5ee6aeae95a..447f210bd56b 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/src/utils/spanUtils.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/src/utils/spanUtils.ts @@ -5,7 +5,7 @@ import { URL } from "url"; import { ReadableSpan } from "@opentelemetry/tracing"; import { hrTimeToMilliseconds } from "@opentelemetry/core"; import { SpanKind, Logger, CanonicalCode, Link } from "@opentelemetry/api"; -import { Envelope, Base } from "../Declarations/Contracts"; +import { Base } from "../Declarations/Contracts"; import { Tags, Properties, MSLink, Measurements } from "../types"; import { HTTP_METHOD, @@ -31,7 +31,7 @@ import { getInstance } from "../platform"; import { DB_STATEMENT, DB_TYPE, DB_INSTANCE } from "./constants/span/dbAttributes"; import { parseEventHubSpan } from "./eventhub"; import { AzNamespace, MicrosoftEventHub } from "./constants/span/azAttributes"; -import { RemoteDependencyData, RequestData } from "../generated"; +import { RemoteDependencyData, RequestData, TelemetryItem as Envelope } from "../generated"; function createTagsFromSpan(span: ReadableSpan): Tags { const context = getInstance(); @@ -193,7 +193,8 @@ export function readableSpanToEnvelope( instrumentationKey: string, logger?: Logger ): Envelope { - const envelope = new Envelope(); + const envelope: Partial = {}; + envelope.sampleRate = 100; envelope.data = new Base(); const tags = createTagsFromSpan(span); const [properties, measurements] = createPropertiesFromSpan(span); @@ -224,22 +225,25 @@ export function readableSpanToEnvelope( throw new Error(`Unsupported span kind ${span.kind}`); } - envelope.data.baseData = { ...data, properties, measurements }; + envelope.data.baseData = { ...data, properties, measurements } as + | RequestData + | RemoteDependencyData; envelope.tags = tags; - envelope.time = new Date(hrTimeToMilliseconds(span.startTime)).toISOString(); - envelope.iKey = instrumentationKey; - envelope.ver = 1; + envelope.time = new Date(hrTimeToMilliseconds(span.startTime)); + envelope.instrumentationKey = instrumentationKey; + envelope.version = 1; if (span.attributes[AzNamespace] === MicrosoftEventHub) { - parseEventHubSpan(span, envelope); + parseEventHubSpan(span, envelope as Envelope); } else if (span.attributes[AzNamespace]) { switch (span.kind) { case SpanKind.INTERNAL: - envelope.data.baseData.type = `${INPROC} | ${span.attributes[AzNamespace]}`; + (envelope.data + .baseData as RemoteDependencyData).type = `${INPROC} | ${span.attributes[AzNamespace]}`; break; default: // no op } } - return envelope; + return envelope as Envelope; } diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts index 220d633f795a..aa8283cce606 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts @@ -2,12 +2,13 @@ // Licensed under the MIT license. import * as assert from "assert"; -import { Base, Envelope } from "../../src/Declarations/Contracts"; +import { Base } from "../../src/Declarations/Contracts"; import { AI_OPERATION_ID, AI_OPERATION_PARENT_ID } from "../../src/utils/constants/applicationinsights"; import { Expectation } from "./scenario/types"; +import { RequestData, TelemetryItem as Envelope } from "../../src/generated"; export const assertData = (actual: Base, expected: Base): void => { assert.strictEqual(actual.baseType, expected.baseType); @@ -23,13 +24,14 @@ export const assertData = (actual: Base, expected: Base): void => { export const assertTrace = (actual: Envelope[], expectation: Expectation): void => { const envelope = actual.filter( - (e) => e.data!.baseData!.name === expectation.data!.baseData!.name + (e) => + (e.data!.baseData as RequestData).name === (expectation.data!.baseData as RequestData).name ); if (envelope.length !== 1) { assert.ok(false, `assertTrace: could not find exported envelope: ${expectation.name}`); return; } - const operationId = envelope[0].tags[AI_OPERATION_ID]; + const operationId = envelope[0].tags![AI_OPERATION_ID]; const parseId = (id: string): { traceId: string; spanId: string } => { const parts = id.replace("|", "").split("."); @@ -41,18 +43,18 @@ export const assertTrace = (actual: Envelope[], expectation: Expectation): void for (const child of expectation.children) { const childEnvelopes = actual.filter((e) => { - const { spanId } = parseId(envelope[0].data!.baseData!.id); + const { spanId } = parseId((envelope[0].data!.baseData as RequestData).id); return ( - e.tags[AI_OPERATION_ID] === operationId && - e.tags[AI_OPERATION_PARENT_ID] === spanId && - e.data!.baseData!.name === child.data!.baseData!.name + e.tags![AI_OPERATION_ID] === operationId && + e.tags![AI_OPERATION_PARENT_ID] === spanId && + (e.data!.baseData as RequestData).name === (child.data!.baseData as RequestData).name ); }); assert.strictEqual( childEnvelopes.length, 1, - `Could not find a child envelope for ${envelope[0].data!.baseData!.name}` + `Could not find a child envelope for ${(envelope[0].data!.baseData as RequestData).name}` ); } }; @@ -70,7 +72,8 @@ export const assertCount = (actual: Envelope[], expectations: Expectation[]): vo export const assertExpectation = (actual: Envelope[], expectations: Expectation[]): void => { for (const expectation of expectations) { const envelope = actual.filter( - (e) => e.data!.baseData!.name === expectation.data!.baseData!.name + (e) => + (e.data!.baseData as RequestData).name === (expectation.data!.baseData as RequestData).name ); if (envelope.length !== 1) { assert.ok(false, `assertExpectation: could not find exported envelope: ${expectation.name}`); @@ -85,11 +88,15 @@ export const assertExpectation = (actual: Envelope[], expectations: Expectation[ break; case "data": if (envelope[0].data) { - assertData(envelope[0].data, value as Base); + assertData(envelope[0].data as Base, value as Base); } break; default: - assert.strictEqual(envelope[0][key], value, `envelope.${key} should be equal`); + assert.strictEqual( + envelope[0][key], + value, + `envelope.${key} should be equal\nActual: ${envelope[0][key]}\nExpected: ${value}` + ); } } } diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/common/scenario/basic.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/common/scenario/basic.ts index 8ccbfeb94465..433f80546cbe 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/common/scenario/basic.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/common/scenario/basic.ts @@ -5,20 +5,23 @@ import * as opentelemetry from "@opentelemetry/api"; import { BasicTracerProvider } from "@opentelemetry/tracing"; import { AzureMonitorTraceExporter } from "../../../src"; import { Expectation, Scenario } from "./types"; -import { Envelope } from "../../../src/Declarations/Contracts"; import { msToTimeSpan } from "../../../src/utils/breezeUtils"; import { CanonicalCode } from "@opentelemetry/api"; import { FlushSpanProcessor } from "../flushSpanProcessor"; import { delay } from "@azure/core-http"; -import { RemoteDependencyData, RequestData } from "../../../src/generated"; +import { + TelemetryItem as Envelope, + RemoteDependencyData, + RequestData +} from "../../../src/generated"; const COMMON_ENVELOPE_PARAMS: Partial = { - iKey: process.env.APPINSIGHTS_INSTRUMENTATIONKEY || "ikey", + instrumentationKey: process.env.APPINSIGHTS_INSTRUMENTATIONKEY || "ikey", sampleRate: 100 }; const exporter = new AzureMonitorTraceExporter({ - instrumentationKey: COMMON_ENVELOPE_PARAMS.iKey + instrumentationKey: COMMON_ENVELOPE_PARAMS.instrumentationKey }); const processor = new FlushSpanProcessor(exporter); @@ -92,8 +95,7 @@ export class BasicScenario implements Scenario { properties: { foo: "bar" } - } as Partial, - properties: undefined + } as Partial }, children: [ { @@ -108,8 +110,7 @@ export class BasicScenario implements Scenario { properties: { numbers: 123 as any } - } as Partial, - properties: undefined + } as Partial }, children: [] }, @@ -125,8 +126,7 @@ export class BasicScenario implements Scenario { properties: { numbers: 1234 as any } - } as Partial, - properties: undefined + } as Partial }, children: [] } diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/common/scenario/types.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/common/scenario/types.ts index 96c061d5a854..5b5eeb784978 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/common/scenario/types.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/common/scenario/types.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { Envelope } from "../../../src/Declarations/Contracts"; +import { TelemetryItem as Envelope } from "../../../src/generated"; export interface Expectation extends Partial { children: Expectation[]; diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/functional/trace.test.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/functional/trace.test.ts index bdc2eac0afd8..ed671fb2073f 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/functional/trace.test.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/functional/trace.test.ts @@ -6,8 +6,8 @@ import { BasicScenario } from "../common/scenario/basic"; import { DEFAULT_BREEZE_ENDPOINT } from "../../src/Declarations/Constants"; import nock from "nock"; import { successfulBreezeResponse } from "../unit/breezeTestUtils"; -import { Envelope } from "../../src/Declarations/Contracts"; import { gunzipSync } from "zlib"; +import { TelemetryItem as Envelope } from "../../src/generated"; describe("Trace Exporter Scenarios", () => { describe(BasicScenario.prototype.constructor.name, () => { diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/export/export.test.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/export/export.test.ts index 31352670eefe..c6340171b8ca 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/export/export.test.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/export/export.test.ts @@ -5,7 +5,6 @@ import * as assert from "assert"; import { ExportResult } from "@opentelemetry/core"; import { AzureMonitorBaseExporter } from "../../../src/export/exporter"; import { TelemetryProcessor } from "../../../src/types"; -import { Envelope } from "../../../src/Declarations/Contracts"; import { DEFAULT_BREEZE_ENDPOINT } from "../../../src/Declarations/Constants"; import { failedBreezeResponse, @@ -13,6 +12,7 @@ import { successfulBreezeResponse } from "../breezeTestUtils"; import { FileSystemPersist } from "../../../src/platform"; +import { TelemetryItem as Envelope } from "../../../src/generated"; import nock = require("nock"); function toObject(obj: T): T { @@ -48,7 +48,10 @@ describe("#AzureMonitorBaseExporter", () => { describe("Sender/Persister Controller", () => { describe("#exportEnvelopes()", () => { const scope = nock(DEFAULT_BREEZE_ENDPOINT).post("/v2/track"); - const envelope = new Envelope(); + const envelope = { + name: "Name", + time: new Date() + }; after(() => { nock.cleanAll(); @@ -158,10 +161,14 @@ describe("#AzureMonitorBaseExporter", () => { describe("#_applyTelemetryProcessors()", () => { it("should filter envelopes", () => { - const fooEnvelope = new Envelope(); - const barEnvelope = new Envelope(); - fooEnvelope.name = "foo"; - barEnvelope.name = "bar"; + const fooEnvelope = { + name: "foo", + time: new Date() + }; + const barEnvelope = { + name: "bar", + time: new Date() + }; const exporter = new TestExporter(); assert.strictEqual(exporter.getTelemetryProcesors().length, 0); @@ -175,10 +182,14 @@ describe("#AzureMonitorBaseExporter", () => { }); it("should filter modified envelopes", () => { - const fooEnvelope = new Envelope(); - const barEnvelope = new Envelope(); - fooEnvelope.name = "foo"; - barEnvelope.name = "bar"; + const fooEnvelope = { + name: "foo", + time: new Date() + }; + const barEnvelope = { + name: "bar", + time: new Date() + }; const exporter = new TestExporter(); assert.strictEqual(exporter.getTelemetryProcesors().length, 0); diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/platform/nodejs/httpSender.test.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/platform/nodejs/httpSender.test.ts index fec353d7b3ad..2bdc5772aa97 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/platform/nodejs/httpSender.test.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/platform/nodejs/httpSender.test.ts @@ -3,13 +3,13 @@ import * as assert from "assert"; import { HttpSender } from "../../../../src/platform/nodejs/httpSender"; -import { Envelope } from "../../../../src/Declarations/Contracts"; import { DEFAULT_BREEZE_ENDPOINT } from "../../../../src/Declarations/Constants"; import { successfulBreezeResponse, failedBreezeResponse, partialBreezeResponse } from "../../breezeTestUtils"; +import { TelemetryItem as Envelope } from "../../../../src/generated"; import nock = require("nock"); describe("HttpSender", () => { @@ -29,7 +29,10 @@ describe("HttpSender", () => { }); describe("#send()", () => { - const envelope = new Envelope(); + const envelope: Envelope = { + name: "name", + time: new Date() + }; it("should send a valid envelope", async () => { const sender = new HttpSender(); scope.reply(200, JSON.stringify(successfulBreezeResponse(1))); diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/platform/nodejs/persist/fileSystemPersist.test.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/platform/nodejs/persist/fileSystemPersist.test.ts index 9f17eecae737..db87bb771c4e 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/platform/nodejs/persist/fileSystemPersist.test.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/platform/nodejs/persist/fileSystemPersist.test.ts @@ -6,7 +6,7 @@ import * as fs from "fs"; import * as os from "os"; import * as path from "path"; import { FileSystemPersist } from "../../../../../src/platform/nodejs/persist/fileSystemPersist"; -import { Envelope } from "../../../../../src/Declarations/Contracts"; +import { TelemetryItem as Envelope } from "../../../../../src/generated"; import { promisify } from "util"; const statAsync = promisify(fs.stat); @@ -73,8 +73,12 @@ describe("FileSystemPersist", () => { describe("#push()", () => { it("should store to disk the value provided", async () => { + const envelope: Envelope = { + name: "name", + time: new Date() + }; const persister = new FileSystemPersist({ instrumentationKey }); - const envelopes = [new Envelope()]; + const envelopes = [envelope]; const success = await persister.push(envelopes); assert.strictEqual(success, true); diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/eventhub.test.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/eventhub.test.ts index 0670244ac83b..0f60e0c257ac 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/eventhub.test.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/eventhub.test.ts @@ -5,7 +5,6 @@ import { Attributes, HrTime, SpanContext, SpanKind } from "@opentelemetry/api"; import { NoopLogger, timeInputToHrTime } from "@opentelemetry/core"; import { BasicTracerProvider, Span } from "@opentelemetry/tracing"; import * as assert from "assert"; -import { Envelope } from "../../../src/Declarations/Contracts"; import { ENQUEUED_TIME, TIME_SINCE_ENQUEUED @@ -16,6 +15,7 @@ import { MicrosoftEventHub } from "../../../src/utils/constants/span/azAttributes"; import { parseEventHubSpan } from "../../../src/utils/eventhub"; +import { RemoteDependencyData, TelemetryItem as Envelope } from "../../../src/generated"; const tracer = new BasicTracerProvider({ logger: new NoopLogger() @@ -53,11 +53,13 @@ describe("#parseEventHubSpan(...)", () => { span.setAttributes(attributes); parseEventHubSpan(span, envelope); - assert.strictEqual(envelope.data?.baseData?.type, attributes[AzNamespace]); - assert.strictEqual(envelope.data?.baseData?.target, `${peerAddress}/${destination}`); - assert.strictEqual(envelope.data?.baseData?.source, undefined); - assert.strictEqual(envelope.data?.baseData?.measurements, undefined); + const baseData = envelope.data?.baseData as RemoteDependencyData; + assert.strictEqual(baseData.type, attributes[AzNamespace]); + assert.strictEqual(baseData.target, `${peerAddress}/${destination}`); + + assert.strictEqual((baseData as any).source, undefined); + assert.strictEqual(baseData.measurements, undefined); }); it("should correctly parse SpanKind.PRODUCER", () => { @@ -71,11 +73,13 @@ describe("#parseEventHubSpan(...)", () => { span.setAttributes(attributes); parseEventHubSpan(span, envelope); - assert.strictEqual(envelope.data?.baseData?.type, `Queue Message | ${attributes[AzNamespace]}`); - assert.strictEqual(envelope.data?.baseData?.target, `${peerAddress}/${destination}`); - assert.strictEqual(envelope.data?.baseData?.source, undefined); - assert.strictEqual(envelope.data?.baseData?.measurements, undefined); + const baseData = envelope.data?.baseData as RemoteDependencyData; + assert.strictEqual(baseData.type, `Queue Message | ${attributes[AzNamespace]}`); + assert.strictEqual(baseData.target, `${peerAddress}/${destination}`); + + assert.strictEqual((baseData as any).source, undefined); + assert.strictEqual(baseData.measurements, undefined); }); it("should correctly parse SpanKind.CONSUMER", () => { @@ -108,12 +112,13 @@ describe("#parseEventHubSpan(...)", () => { span.setAttributes(attributes); parseEventHubSpan(span, envelope); - assert.strictEqual(envelope.data?.baseData?.type, `Queue Message | ${attributes[AzNamespace]}`); - assert.strictEqual(envelope.data?.baseData?.source, `${peerAddress}/${destination}`); - assert.deepStrictEqual(envelope.data?.baseData?.measurements, { + const baseData = envelope.data?.baseData as RemoteDependencyData; + assert.strictEqual(baseData.type, `Queue Message | ${attributes[AzNamespace]}`); + assert.strictEqual((baseData as any).source, `${peerAddress}/${destination}`); + assert.deepStrictEqual(baseData.measurements, { [TIME_SINCE_ENQUEUED]: 148 }); - assert.strictEqual(envelope.data?.baseData?.target, undefined); + assert.strictEqual(baseData.target, undefined); }); }); diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/spanUtils.test.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/spanUtils.test.ts index 06443c2b54d9..7e0a8e1df431 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/spanUtils.test.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/spanUtils.test.ts @@ -7,7 +7,6 @@ import * as assert from "assert"; import { NoopLogger, hrTimeToMilliseconds } from "@opentelemetry/core"; import { Tags, Properties, Measurements } from "../../../src/types"; -import { Envelope } from "../../../src/Declarations/Contracts"; import * as http from "../../../src/utils/constants/span/httpAttributes"; import * as grpc from "../../../src/utils/constants/span/grpcAttributes"; import * as ai from "../../../src/utils/constants/applicationinsights"; @@ -15,6 +14,7 @@ import { Context, getInstance } from "../../../src/platform"; import { msToTimeSpan } from "../../../src/utils/breezeUtils"; import { readableSpanToEnvelope } from "../../../src/utils/spanUtils"; import { RemoteDependencyData, RequestData } from "../../../src/generated"; +import { TelemetryItem as Envelope } from "../../../src/generated"; const context = getInstance(undefined, "./", "../../"); @@ -30,7 +30,7 @@ function assertEnvelope( expectedProperties: Properties, expectedMeasurements: Measurements | undefined, expectedBaseData: Partial, - expectedTime?: string + expectedTime?: Date ) { assert.strictEqual(Context.sdkVersion, ai.packageVersion); assert.strictEqual(Object.keys(Context.appVersion).length, 1); @@ -40,18 +40,21 @@ function assertEnvelope( assert.strictEqual(envelope.name, name); assert.deepStrictEqual(envelope.data?.baseType, baseType); - assert.strictEqual(envelope.iKey, "ikey"); + assert.strictEqual(envelope.instrumentationKey, "ikey"); assert.ok(envelope.time); - assert.ok(envelope.ver); + assert.ok(envelope.version); assert.ok(envelope.data); if (expectedTime) { - assert.strictEqual(envelope.time, expectedTime); + assert.strictEqual(envelope.time.toISOString(), expectedTime.toISOString()); } assert.deepStrictEqual(envelope.tags, { ...context.tags, ...expectedTags }); - assert.deepStrictEqual(envelope?.data?.baseData?.properties, expectedProperties); - assert.deepStrictEqual(envelope?.data?.baseData?.measurements, expectedMeasurements); + assert.deepStrictEqual((envelope?.data?.baseData as RequestData).properties, expectedProperties); + assert.deepStrictEqual( + (envelope?.data?.baseData as RequestData).measurements, + expectedMeasurements + ); assert.deepStrictEqual(envelope.data?.baseData, expectedBaseData); } @@ -187,7 +190,7 @@ describe("spanUtils.ts", () => { code: CanonicalCode.OK }); span.end(); - const expectedTime = new Date(hrTimeToMilliseconds(span.startTime)).toISOString(); + const expectedTime = new Date(hrTimeToMilliseconds(span.startTime)); const expectedTags: Tags = { [ai.AI_OPERATION_ID]: "traceid", [ai.AI_OPERATION_PARENT_ID]: "parentSpanId" From e060a902bbbd5a24f04a40472c53ddbc558e42a8 Mon Sep 17 00:00:00 2001 From: Mark Wolff Date: Thu, 17 Sep 2020 11:40:33 -0700 Subject: [PATCH 02/13] integrate with generated client --- .../src/platform/nodejs/httpSender.ts | 55 ++++++------------- .../src/platform/types.ts | 21 ------- .../test/common/assert.ts | 7 ++- .../test/functional/trace.test.ts | 7 ++- .../test/unit/export/export.test.ts | 10 +++- .../test/unit/utils/spanUtils.test.ts | 2 +- 6 files changed, 36 insertions(+), 66 deletions(-) delete mode 100644 sdk/monitor/monitor-opentelemetry-exporter/src/platform/types.ts diff --git a/sdk/monitor/monitor-opentelemetry-exporter/src/platform/nodejs/httpSender.ts b/sdk/monitor/monitor-opentelemetry-exporter/src/platform/nodejs/httpSender.ts index 4db63063e570..802519f8a4c9 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/src/platform/nodejs/httpSender.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/src/platform/nodejs/httpSender.ts @@ -1,54 +1,35 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import * as zlib from "zlib"; import { Logger } from "@opentelemetry/api"; import { ConsoleLogger, LogLevel } from "@opentelemetry/core"; import { Sender, SenderResult } from "../../types"; -import { TelemetryItem as Envelope } from "../../generated"; -import { DEFAULT_SENDER_OPTIONS, NodejsPlatformConfig } from "../types"; -import { promisify } from "util"; -import { DefaultHttpClient, HttpClient, HttpHeaders, WebResource } from "@azure/core-http"; - -const gzipAsync = promisify(zlib.gzip); +import { + TelemetryItem as Envelope, + ApplicationInsightsClient, + ApplicationInsightsClientOptionalParams +} from "../../generated"; +import { AzureExporterConfig } from "../../config"; export class HttpSender implements Sender { private readonly _logger: Logger; - private readonly _httpClient: HttpClient; + private readonly _appInsightsClient: ApplicationInsightsClient; - constructor(private _options: NodejsPlatformConfig = DEFAULT_SENDER_OPTIONS) { - this._logger = _options.logger || new ConsoleLogger(LogLevel.ERROR); - this._httpClient = new DefaultHttpClient(); + constructor( + private _exporterOptions: Partial = {}, + private _appInsightsClientOptions: ApplicationInsightsClientOptionalParams = {} + ) { + this._logger = this._exporterOptions.logger || new ConsoleLogger(LogLevel.ERROR); + this._appInsightsClient = new ApplicationInsightsClient({ + ...this._appInsightsClientOptions + }); } async send(envelopes: Envelope[]): Promise { - const endpointUrl = `${this._options.endpointUrl}/v2/track`; - const payload = Buffer.from(JSON.stringify(envelopes)); - - const headers = new HttpHeaders({ "Content-Type": "application/x-json-stream" }); - - let dataToSend: Buffer; - try { - dataToSend = await gzipAsync(payload); - headers.set("Content-Encoding", "gzip"); - } catch (err) { - this._logger.warn(`Failed to gzip payload: ${err.message}. Sending payload uncompressed`); - dataToSend = payload; // something went wrong so send without gzip - } - headers.set("Content-Length", dataToSend.length); - - const options = new WebResource( - endpointUrl, - "POST", - dataToSend, - undefined, - headers, - undefined, - false // withCredentials: false - ); - const res = await this._httpClient.sendRequest(options); - return { statusCode: res.status, result: res.bodyAsText || "" }; + const res = await this._appInsightsClient.track(envelopes); + // eslint-disable-next-line no-underscore-dangle + return { statusCode: res._response.status, result: res._response.bodyAsText || "" }; } shutdown(): void { diff --git a/sdk/monitor/monitor-opentelemetry-exporter/src/platform/types.ts b/sdk/monitor/monitor-opentelemetry-exporter/src/platform/types.ts deleted file mode 100644 index d06238b660ff..000000000000 --- a/sdk/monitor/monitor-opentelemetry-exporter/src/platform/types.ts +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import * as http from "http"; -import * as https from "https"; -import { DEFAULT_EXPORTER_CONFIG, AzureExporterConfig } from "../config"; - -/** - * Node.js and platform specific - */ -export interface NodejsPlatformConfig extends AzureExporterConfig { - proxyHttpsUrl?: string; - proxyHttpUrl?: string; - httpAgent?: http.Agent; - httpsAgent?: https.Agent; -} - -// Noop for now until sender requires -export const DEFAULT_SENDER_OPTIONS: NodejsPlatformConfig = { - ...DEFAULT_EXPORTER_CONFIG, -}; diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts index aa8283cce606..ec321e9688ef 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts @@ -76,7 +76,12 @@ export const assertExpectation = (actual: Envelope[], expectations: Expectation[ (e.data!.baseData as RequestData).name === (expectation.data!.baseData as RequestData).name ); if (envelope.length !== 1) { - assert.ok(false, `assertExpectation: could not find exported envelope: ${expectation.name}`); + assert.ok( + false, + `assertExpectation: could not find exported envelope: ${ + (expectation.data?.baseData as RequestData).name + }` + ); return; } diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/functional/trace.test.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/functional/trace.test.ts index ed671fb2073f..16b327ac4799 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/functional/trace.test.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/functional/trace.test.ts @@ -6,7 +6,6 @@ import { BasicScenario } from "../common/scenario/basic"; import { DEFAULT_BREEZE_ENDPOINT } from "../../src/Declarations/Constants"; import nock from "nock"; import { successfulBreezeResponse } from "../unit/breezeTestUtils"; -import { gunzipSync } from "zlib"; import { TelemetryItem as Envelope } from "../../src/generated"; describe("Trace Exporter Scenarios", () => { @@ -16,8 +15,10 @@ describe("Trace Exporter Scenarios", () => { let ingest: Envelope[] = []; nock(DEFAULT_BREEZE_ENDPOINT) .post("/v2/track", (body) => { - const buffer = gunzipSync(Buffer.from(body, "hex")); - ingest.push(...(JSON.parse(buffer.toString("utf8")) as Envelope[])); + // todo: gzip is not supported by generated applicationInsightsClient + // const buffer = gunzipSync(Buffer.from(body, "hex")); + // ingest.push(...(JSON.parse(buffer.toString("utf8")) as Envelope[])); + ingest.push(body); return body; }) .reply(200, successfulBreezeResponse(1)) diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/export/export.test.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/export/export.test.ts index c6340171b8ca..f17f638fea11 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/export/export.test.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/export/export.test.ts @@ -23,7 +23,7 @@ describe("#AzureMonitorBaseExporter", () => { class TestExporter extends AzureMonitorBaseExporter { constructor() { super({ - instrumentationKey: "foo" + instrumentationKey: "foo-ikey" }); } @@ -53,14 +53,18 @@ describe("#AzureMonitorBaseExporter", () => { time: new Date() }; + before(() => { + nock.cleanAll(); + }); + after(() => { nock.cleanAll(); }); it("should persist retriable failed telemetry", async () => { const exporter = new TestExporter(); - const response = failedBreezeResponse(1, 408); - scope.reply(408, JSON.stringify(response)); + const response = failedBreezeResponse(1, 429); + scope.reply(429, JSON.stringify(response)); const result = await exporter.exportEnvelopes([envelope]); assert.strictEqual(result, ExportResult.FAILED_RETRYABLE); diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/spanUtils.test.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/spanUtils.test.ts index 7e0a8e1df431..974a6a9187bf 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/spanUtils.test.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/spanUtils.test.ts @@ -31,7 +31,7 @@ function assertEnvelope( expectedMeasurements: Measurements | undefined, expectedBaseData: Partial, expectedTime?: Date -) { +): void { assert.strictEqual(Context.sdkVersion, ai.packageVersion); assert.strictEqual(Object.keys(Context.appVersion).length, 1); assert.notDeepStrictEqual(Context.appVersion, "unknown"); From 0e2cfb63cb4512a9e002f0db2168cc9cebd7d660 Mon Sep 17 00:00:00 2001 From: Mark Wolff Date: Thu, 17 Sep 2020 15:15:47 -0700 Subject: [PATCH 03/13] run tests on serialized payloads --- .../monitor-opentelemetry-exporter/test/common/assert.ts | 7 +++++-- .../test/functional/trace.test.ts | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts index ec321e9688ef..6d2455fbe0f4 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts @@ -9,6 +9,7 @@ import { } from "../../src/utils/constants/applicationinsights"; import { Expectation } from "./scenario/types"; import { RequestData, TelemetryItem as Envelope } from "../../src/generated"; +import {TelemetryItem as EnvelopeMapper} from '../../src/generated/models/mappers'; export const assertData = (actual: Base, expected: Base): void => { assert.strictEqual(actual.baseType, expected.baseType); @@ -86,6 +87,7 @@ export const assertExpectation = (actual: Envelope[], expectations: Expectation[ } for (const [key, value] of Object.entries(expectation) as [keyof Expectation, unknown][]) { + const serializedKey = EnvelopeMapper.type.modelProperties![key]?.serializedName ?? undefined; switch (key) { case "children": assertTrace(actual, expectation); @@ -97,10 +99,11 @@ export const assertExpectation = (actual: Envelope[], expectations: Expectation[ } break; default: + assert.ok(serializedKey, `Serialized key for ${key}`); assert.strictEqual( - envelope[0][key], + envelope[0][serializedKey as keyof Envelope], // as keyof Serialized(Envelope) value, - `envelope.${key} should be equal\nActual: ${envelope[0][key]}\nExpected: ${value}` + `envelope.${serializedKey} should be equal\nActual: ${envelope[0][key]}\nExpected: ${value}` ); } } diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/functional/trace.test.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/functional/trace.test.ts index 16b327ac4799..b189bb7514d1 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/functional/trace.test.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/functional/trace.test.ts @@ -14,12 +14,12 @@ describe("Trace Exporter Scenarios", () => { let ingest: Envelope[] = []; nock(DEFAULT_BREEZE_ENDPOINT) - .post("/v2/track", (body) => { + .post("/v2/track", (body: Envelope[]) => { // todo: gzip is not supported by generated applicationInsightsClient // const buffer = gunzipSync(Buffer.from(body, "hex")); // ingest.push(...(JSON.parse(buffer.toString("utf8")) as Envelope[])); - ingest.push(body); - return body; + ingest.push(...body); + return true; }) .reply(200, successfulBreezeResponse(1)) .persist(); From c1ca84a156d0c1cf0a4462569806eb0cf1c1b599 Mon Sep 17 00:00:00 2001 From: Mark Wolff Date: Thu, 17 Sep 2020 15:16:14 -0700 Subject: [PATCH 04/13] prettier update --- .../monitor-opentelemetry-exporter/test/common/assert.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts index 6d2455fbe0f4..e8e20be8a2ee 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts @@ -9,7 +9,7 @@ import { } from "../../src/utils/constants/applicationinsights"; import { Expectation } from "./scenario/types"; import { RequestData, TelemetryItem as Envelope } from "../../src/generated"; -import {TelemetryItem as EnvelopeMapper} from '../../src/generated/models/mappers'; +import { TelemetryItem as EnvelopeMapper } from "../../src/generated/models/mappers"; export const assertData = (actual: Base, expected: Base): void => { assert.strictEqual(actual.baseType, expected.baseType); From f6c4960a2fb1e01b0aea9caa82291b629acdd8be Mon Sep 17 00:00:00 2001 From: Mark Wolff Date: Mon, 21 Sep 2020 12:53:53 -0700 Subject: [PATCH 05/13] test on latest swagger --- .../src/utils/spanUtils.ts | 3 +-- .../test/common/scenario/basic.ts | 9 ++++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/sdk/monitor/monitor-opentelemetry-exporter/src/utils/spanUtils.ts b/sdk/monitor/monitor-opentelemetry-exporter/src/utils/spanUtils.ts index 447f210bd56b..e04de75f392f 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/src/utils/spanUtils.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/src/utils/spanUtils.ts @@ -5,7 +5,6 @@ import { URL } from "url"; import { ReadableSpan } from "@opentelemetry/tracing"; import { hrTimeToMilliseconds } from "@opentelemetry/core"; import { SpanKind, Logger, CanonicalCode, Link } from "@opentelemetry/api"; -import { Base } from "../Declarations/Contracts"; import { Tags, Properties, MSLink, Measurements } from "../types"; import { HTTP_METHOD, @@ -195,7 +194,7 @@ export function readableSpanToEnvelope( ): Envelope { const envelope: Partial = {}; envelope.sampleRate = 100; - envelope.data = new Base(); + envelope.data = {}; const tags = createTagsFromSpan(span); const [properties, measurements] = createPropertiesFromSpan(span); let data; diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/common/scenario/basic.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/common/scenario/basic.ts index 433f80546cbe..19c04b2d4fb5 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/common/scenario/basic.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/common/scenario/basic.ts @@ -88,6 +88,7 @@ export class BasicScenario implements Scenario { data: { baseType: "RequestData", baseData: { + version: 1, name: "BasicScenario.Root", duration: msToTimeSpan(600), responseCode: "0", @@ -95,7 +96,7 @@ export class BasicScenario implements Scenario { properties: { foo: "bar" } - } as Partial + } as Omit }, children: [ { @@ -103,6 +104,7 @@ export class BasicScenario implements Scenario { data: { baseType: "RemoteDependencyData", baseData: { + version: 1, name: "BasicScenario.Child.1", duration: msToTimeSpan(100), success: true, @@ -110,7 +112,7 @@ export class BasicScenario implements Scenario { properties: { numbers: 123 as any } - } as Partial + } as Omit }, children: [] }, @@ -119,6 +121,7 @@ export class BasicScenario implements Scenario { data: { baseType: "RemoteDependencyData", baseData: { + version: 1, name: "BasicScenario.Child.2", duration: msToTimeSpan(100), success: true, @@ -126,7 +129,7 @@ export class BasicScenario implements Scenario { properties: { numbers: 1234 as any } - } as Partial + } as Omit }, children: [] } From 0cd137b067233325fbe349a3c5f6b3e31ccbc65b Mon Sep 17 00:00:00 2001 From: Mark Wolff Date: Tue, 22 Sep 2020 16:49:39 -0700 Subject: [PATCH 06/13] check in mock swagger --- .../src/generated/models/index.ts | 368 +--------- .../src/generated/models/mappers.ts | 682 +----------------- .../src/utils/spanUtils.ts | 11 +- .../swagger/README.md | 3 +- .../swagger/swagger.json | 512 +++++++++++++ .../test/common/scenario/basic.ts | 12 +- .../test/functional/trace.test.ts | 1 + .../test/unit/utils/spanUtils.test.ts | 2 + 8 files changed, 583 insertions(+), 1008 deletions(-) create mode 100644 sdk/monitor/monitor-opentelemetry-exporter/swagger/swagger.json diff --git a/sdk/monitor/monitor-opentelemetry-exporter/src/generated/models/index.ts b/sdk/monitor/monitor-opentelemetry-exporter/src/generated/models/index.ts index f993f333b3fa..6cd3bd71b189 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/src/generated/models/index.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/src/generated/models/index.ts @@ -8,6 +8,11 @@ import * as coreHttp from "@azure/core-http"; +export type MonitorDomainUnion = + | MonitorDomain + | RemoteDependencyData + | RequestData; + /** * System variables for a telemetry item. */ @@ -57,7 +62,7 @@ export interface MonitorBase { /** * The data payload for the telemetry request */ - baseData?: MonitorDomain; + baseData?: MonitorDomainUnion; } /** @@ -65,9 +70,13 @@ export interface MonitorBase { */ export interface MonitorDomain { /** - * Ignored value. + * Polymorphic discriminator, which specifies the different types this object can be + */ + typename: "RemoteDependencyData" | "RequestData"; + /** + * Schema version */ - test?: string; + version: number; } /** @@ -106,339 +115,10 @@ export interface TelemetryErrorDetails { message?: string; } -/** - * Metric data single measurement. - */ -export interface MetricDataPoint { - /** - * Namespace of the metric. - */ - namespace?: string; - /** - * Name of the metric. - */ - name: string; - /** - * Metric type. Single measurement or the aggregated value. - */ - dataPointType?: DataPointType; - /** - * Single value for measurement. Sum of individual measurements for the aggregation. - */ - value: number; - /** - * Metric weight of the aggregated metric. Should not be set for a measurement. - */ - count?: number; - /** - * Minimum value of the aggregated metric. Should not be set for a measurement. - */ - min?: number; - /** - * Maximum value of the aggregated metric. Should not be set for a measurement. - */ - max?: number; - /** - * Standard deviation of the aggregated metric. Should not be set for a measurement. - */ - stdDev?: number; -} - -/** - * Exception details of the exception in a chain. - */ -export interface TelemetryExceptionDetails { - /** - * In case exception is nested (outer exception contains inner one), the id and outerId properties are used to represent the nesting. - */ - id?: number; - /** - * The value of outerId is a reference to an element in ExceptionDetails that represents the outer exception - */ - outerId?: number; - /** - * Exception type name. - */ - typeName?: string; - /** - * Exception message. - */ - message: string; - /** - * Indicates if full exception stack is provided in the exception. The stack may be trimmed, such as in the case of a StackOverflow exception. - */ - hasFullStack?: boolean; - /** - * Text describing the stack. Either stack or parsedStack should have a value. - */ - stack?: string; - /** - * List of stack frames. Either stack or parsedStack should have a value. - */ - parsedStack?: StackFrame[]; -} - -/** - * Stack frame information. - */ -export interface StackFrame { - level: number; - /** - * Method name. - */ - method: string; - /** - * Name of the assembly (dll, jar, etc.) containing this function. - */ - assembly?: string; - /** - * File name or URL of the method implementation. - */ - fileName?: string; - /** - * Line number of the code implementation. - */ - line?: number; -} - -/** - * Instances of AvailabilityData represent the result of executing an availability test. - */ -export type AvailabilityData = MonitorDomain & { - /** - * Schema version - */ - version: number; - /** - * Identifier of a test run. Use it to correlate steps of test run and telemetry generated by the service. - */ - id: string; - /** - * Name of the test that these availability results represent. - */ - name: string; - /** - * Duration in format: DD.HH:MM:SS.MMMMMM. Must be less than 1000 days. - */ - duration: string; - /** - * Success flag. - */ - success: boolean; - /** - * Name of the location where the test was run from. - */ - runLocation?: string; - /** - * Diagnostic message for the result. - */ - message?: string; - /** - * Collection of custom properties. - */ - properties?: { [propertyName: string]: string }; - /** - * Collection of custom measurements. - */ - measurements?: { [propertyName: string]: number }; -}; - -/** - * 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. - */ -export type TelemetryEventData = MonitorDomain & { - /** - * Schema version - */ - version: number; - /** - * Event name. Keep it low cardinality to allow proper grouping and useful metrics. - */ - name: string; - /** - * Collection of custom properties. - */ - properties?: { [propertyName: string]: string }; - /** - * Collection of custom measurements. - */ - measurements?: { [propertyName: string]: number }; -}; - -/** - * An instance of Exception represents a handled or unhandled exception that occurred during execution of the monitored application. - */ -export type TelemetryExceptionData = MonitorDomain & { - /** - * Schema version - */ - version: number; - /** - * Exception chain - list of inner exceptions. - */ - exceptions?: TelemetryExceptionDetails[]; - /** - * Severity level. Mostly used to indicate exception severity level when it is reported by logging library. - */ - severityLevel?: SeverityLevel; - /** - * 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. - */ - problemId?: string; - /** - * Collection of custom properties. - */ - properties?: { [propertyName: string]: string }; - /** - * Collection of custom measurements. - */ - measurements?: { [propertyName: string]: number }; -}; - -/** - * 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. - */ -export type MessageData = MonitorDomain & { - /** - * Schema version - */ - version: number; - /** - * Trace message - */ - message: string; - /** - * Trace severity level. - */ - severityLevel?: SeverityLevel; - /** - * Collection of custom properties. - */ - properties?: { [propertyName: string]: string }; - /** - * Collection of custom measurements. - */ - measurements?: { [propertyName: string]: number }; -}; - -/** - * An instance of the Metric item is a list of measurements (single data points) and/or aggregations. - */ -export type MetricsData = MonitorDomain & { - /** - * Schema version - */ - version: number; - /** - * List of metrics. Only one metric in the list is currently supported by Application Insights storage. If multiple data points were sent only the first one will be used. - */ - metrics: MetricDataPoint[]; - /** - * Collection of custom properties. - */ - properties?: { [propertyName: string]: string }; -}; - -/** - * An instance of PageView represents a generic action on a page like a button click. It is also the base type for PageView. - */ -export type PageViewData = MonitorDomain & { - /** - * Schema version - */ - version: number; - /** - * Identifier of a page view instance. Used for correlation between page view and other telemetry items. - */ - id: string; - /** - * Event name. Keep it low cardinality to allow proper grouping and useful metrics. - */ - name: string; - /** - * Request URL with all query string parameters - */ - url?: string; - /** - * Request duration in format: DD.HH:MM:SS.MMMMMM. For a page view (PageViewData), this is the duration. For a page view with performance information (PageViewPerfData), this is the page load time. Must be less than 1000 days. - */ - duration?: string; - /** - * Fully qualified page URI or URL of the referring page; if unknown, leave blank - */ - referredUri?: string; - /** - * Collection of custom properties. - */ - properties?: { [propertyName: string]: string }; - /** - * Collection of custom measurements. - */ - measurements?: { [propertyName: string]: number }; -}; - -/** - * 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. - */ -export type PageViewPerfData = MonitorDomain & { - /** - * Schema version - */ - version: number; - /** - * Identifier of a page view instance. Used for correlation between page view and other telemetry items. - */ - id: string; - /** - * Event name. Keep it low cardinality to allow proper grouping and useful metrics. - */ - name: string; - /** - * Request URL with all query string parameters - */ - url?: string; - /** - * Request duration in format: DD.HH:MM:SS.MMMMMM. For a page view (PageViewData), this is the duration. For a page view with performance information (PageViewPerfData), this is the page load time. Must be less than 1000 days. - */ - duration?: string; - /** - * Performance total in TimeSpan 'G' (general long) format: d:hh:mm:ss.fffffff - */ - perfTotal?: string; - /** - * Network connection time in TimeSpan 'G' (general long) format: d:hh:mm:ss.fffffff - */ - networkConnect?: string; - /** - * Sent request time in TimeSpan 'G' (general long) format: d:hh:mm:ss.fffffff - */ - sentRequest?: string; - /** - * Received response time in TimeSpan 'G' (general long) format: d:hh:mm:ss.fffffff - */ - receivedResponse?: string; - /** - * DOM processing time in TimeSpan 'G' (general long) format: d:hh:mm:ss.fffffff - */ - domProcessing?: string; - /** - * Collection of custom properties. - */ - properties?: { [propertyName: string]: string }; - /** - * Collection of custom measurements. - */ - measurements?: { [propertyName: string]: number }; -}; - /** * An instance of Remote Dependency represents an interaction of the monitored component with a remote component/service like SQL or an HTTP endpoint. */ export type RemoteDependencyData = MonitorDomain & { - /** - * Schema version - */ - version: number; /** * Identifier of a dependency call instance. Used for correlation with the request telemetry item corresponding to this dependency call. */ @@ -452,7 +132,7 @@ export type RemoteDependencyData = MonitorDomain & { */ resultCode?: string; /** - * Command initiated by this dependency call. Examples are SQL statement and HTTP URL's with all query parameters. + * Command initiated by this dependency call. Examples are SQL statement and HTTP URL with all query parameters. */ data?: string; /** @@ -468,7 +148,7 @@ export type RemoteDependencyData = MonitorDomain & { */ duration: string; /** - * Indication of successfull or unsuccessfull call. + * Indication of successful or unsuccessful call. */ success?: boolean; /** @@ -485,10 +165,6 @@ export type RemoteDependencyData = MonitorDomain & { * An instance of PageView represents a generic action on a page like a button click. It is also the base type for PageView. */ export type RequestData = MonitorDomain & { - /** - * Schema version - */ - version: number; /** * Identifier of a request call instance. Used for correlation between request and other telemetry items. */ @@ -502,7 +178,7 @@ export type RequestData = MonitorDomain & { */ duration: string; /** - * Indication of successfull or unsuccessfull call. + * Indication of successful or unsuccessful call. */ success: boolean; /** @@ -526,20 +202,6 @@ export type RequestData = MonitorDomain & { */ measurements?: { [propertyName: string]: number }; }; -/** - * Defines values for DataPointType. - */ -export type DataPointType = "Measurement" | "Aggregation" | string; -/** - * Defines values for SeverityLevel. - */ -export type SeverityLevel = - | "Verbose" - | "Information" - | "Warning" - | "Error" - | "Critical" - | string; /** * Defines values for ContextTagKeys. */ diff --git a/sdk/monitor/monitor-opentelemetry-exporter/src/generated/models/mappers.ts b/sdk/monitor/monitor-opentelemetry-exporter/src/generated/models/mappers.ts index d7e585c7c8ed..4cd4b1da50ec 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/src/generated/models/mappers.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/src/generated/models/mappers.ts @@ -100,384 +100,12 @@ export const MonitorDomain: coreHttp.CompositeMapper = { type: { name: "Composite", className: "MonitorDomain", + uberParent: "MonitorDomain", + polymorphicDiscriminator: { + serializedName: "typename", + clientName: "typename" + }, modelProperties: { - test: { - serializedName: "test", - type: { - name: "String" - } - } - } - } -}; - -export const TrackResponse: coreHttp.CompositeMapper = { - type: { - name: "Composite", - className: "TrackResponse", - modelProperties: { - itemsReceived: { - serializedName: "itemsReceived", - type: { - name: "Number" - } - }, - itemsAccepted: { - serializedName: "itemsAccepted", - type: { - name: "Number" - } - }, - errors: { - serializedName: "errors", - type: { - name: "Sequence", - element: { - type: { name: "Composite", className: "TelemetryErrorDetails" } - } - } - } - } - } -}; - -export const TelemetryErrorDetails: coreHttp.CompositeMapper = { - type: { - name: "Composite", - className: "TelemetryErrorDetails", - modelProperties: { - index: { - serializedName: "index", - type: { - name: "Number" - } - }, - statusCode: { - serializedName: "statusCode", - type: { - name: "Number" - } - }, - message: { - serializedName: "message", - type: { - name: "String" - } - } - } - } -}; - -export const MetricDataPoint: coreHttp.CompositeMapper = { - type: { - name: "Composite", - className: "MetricDataPoint", - modelProperties: { - namespace: { - constraints: { - MaxLength: 256 - }, - serializedName: "ns", - type: { - name: "String" - } - }, - name: { - constraints: { - MaxLength: 1024 - }, - serializedName: "name", - required: true, - type: { - name: "String" - } - }, - dataPointType: { - serializedName: "kind", - type: { - name: "String" - } - }, - value: { - serializedName: "value", - required: true, - type: { - name: "Number" - } - }, - count: { - serializedName: "count", - type: { - name: "Number" - } - }, - min: { - serializedName: "min", - type: { - name: "Number" - } - }, - max: { - serializedName: "max", - type: { - name: "Number" - } - }, - stdDev: { - serializedName: "stdDev", - type: { - name: "Number" - } - } - } - } -}; - -export const TelemetryExceptionDetails: coreHttp.CompositeMapper = { - type: { - name: "Composite", - className: "TelemetryExceptionDetails", - modelProperties: { - id: { - serializedName: "id", - type: { - name: "Number" - } - }, - outerId: { - serializedName: "outerId", - type: { - name: "Number" - } - }, - typeName: { - constraints: { - MaxLength: 1024 - }, - serializedName: "typeName", - type: { - name: "String" - } - }, - message: { - constraints: { - MaxLength: 32768 - }, - serializedName: "message", - required: true, - type: { - name: "String" - } - }, - hasFullStack: { - defaultValue: true, - serializedName: "hasFullStack", - type: { - name: "Boolean" - } - }, - stack: { - constraints: { - MaxLength: 32768 - }, - serializedName: "stack", - type: { - name: "String" - } - }, - parsedStack: { - serializedName: "parsedStack", - type: { - name: "Sequence", - element: { type: { name: "Composite", className: "StackFrame" } } - } - } - } - } -}; - -export const StackFrame: coreHttp.CompositeMapper = { - type: { - name: "Composite", - className: "StackFrame", - modelProperties: { - level: { - serializedName: "level", - required: true, - type: { - name: "Number" - } - }, - method: { - constraints: { - MaxLength: 1024 - }, - serializedName: "method", - required: true, - type: { - name: "String" - } - }, - assembly: { - constraints: { - MaxLength: 1024 - }, - serializedName: "assembly", - type: { - name: "String" - } - }, - fileName: { - constraints: { - MaxLength: 1024 - }, - serializedName: "fileName", - type: { - name: "String" - } - }, - line: { - serializedName: "line", - type: { - name: "Number" - } - } - } - } -}; - -export const AvailabilityData: coreHttp.CompositeMapper = { - type: { - name: "Composite", - className: "AvailabilityData", - modelProperties: { - ...MonitorDomain.type.modelProperties, - version: { - defaultValue: 2, - serializedName: "ver", - required: true, - type: { - name: "Number" - } - }, - id: { - constraints: { - MaxLength: 512 - }, - serializedName: "id", - required: true, - type: { - name: "String" - } - }, - name: { - constraints: { - MaxLength: 1024 - }, - serializedName: "name", - required: true, - type: { - name: "String" - } - }, - duration: { - serializedName: "duration", - required: true, - type: { - name: "String" - } - }, - success: { - serializedName: "success", - required: true, - type: { - name: "Boolean" - } - }, - runLocation: { - constraints: { - MaxLength: 1024 - }, - serializedName: "runLocation", - type: { - name: "String" - } - }, - message: { - constraints: { - MaxLength: 8192 - }, - serializedName: "message", - type: { - name: "String" - } - }, - properties: { - serializedName: "properties", - type: { - name: "Dictionary", - value: { type: { name: "String" }, constraints: { MaxLength: 8192 } } - } - }, - measurements: { - serializedName: "measurements", - type: { - name: "Dictionary", - value: { type: { name: "Number" } } - } - } - } - } -}; - -export const TelemetryEventData: coreHttp.CompositeMapper = { - type: { - name: "Composite", - className: "TelemetryEventData", - modelProperties: { - ...MonitorDomain.type.modelProperties, - version: { - defaultValue: 2, - serializedName: "ver", - required: true, - type: { - name: "Number" - } - }, - name: { - constraints: { - MaxLength: 512 - }, - serializedName: "name", - required: true, - type: { - name: "String" - } - }, - properties: { - serializedName: "properties", - type: { - name: "Dictionary", - value: { type: { name: "String" }, constraints: { MaxLength: 8192 } } - } - }, - measurements: { - serializedName: "measurements", - type: { - name: "Dictionary", - value: { type: { name: "Number" } } - } - } - } - } -}; - -export const TelemetryExceptionData: coreHttp.CompositeMapper = { - type: { - name: "Composite", - className: "TelemetryExceptionData", - modelProperties: { - ...MonitorDomain.type.modelProperties, version: { defaultValue: 2, serializedName: "ver", @@ -486,316 +114,83 @@ export const TelemetryExceptionData: coreHttp.CompositeMapper = { name: "Number" } }, - exceptions: { - serializedName: "exceptions", - type: { - name: "Sequence", - element: { - type: { name: "Composite", className: "TelemetryExceptionDetails" } - } - } - }, - severityLevel: { - serializedName: "severityLevel", - type: { - name: "String" - } - }, - problemId: { - constraints: { - MaxLength: 1024 - }, - serializedName: "problemId", + typename: { + serializedName: "typename", + required: true, type: { name: "String" } - }, - properties: { - serializedName: "properties", - type: { - name: "Dictionary", - value: { type: { name: "String" }, constraints: { MaxLength: 8192 } } - } - }, - measurements: { - serializedName: "measurements", - type: { - name: "Dictionary", - value: { type: { name: "Number" } } - } } } } }; -export const MessageData: coreHttp.CompositeMapper = { +export const TrackResponse: coreHttp.CompositeMapper = { type: { name: "Composite", - className: "MessageData", + className: "TrackResponse", modelProperties: { - ...MonitorDomain.type.modelProperties, - version: { - defaultValue: 2, - serializedName: "ver", - required: true, + itemsReceived: { + serializedName: "itemsReceived", type: { name: "Number" } }, - message: { - constraints: { - MaxLength: 32768 - }, - serializedName: "message", - required: true, - type: { - name: "String" - } - }, - severityLevel: { - serializedName: "severityLevel", - type: { - name: "String" - } - }, - properties: { - serializedName: "properties", - type: { - name: "Dictionary", - value: { type: { name: "String" }, constraints: { MaxLength: 8192 } } - } - }, - measurements: { - serializedName: "measurements", - type: { - name: "Dictionary", - value: { type: { name: "Number" } } - } - } - } - } -}; - -export const MetricsData: coreHttp.CompositeMapper = { - type: { - name: "Composite", - className: "MetricsData", - modelProperties: { - ...MonitorDomain.type.modelProperties, - version: { - defaultValue: 2, - serializedName: "ver", - required: true, + itemsAccepted: { + serializedName: "itemsAccepted", type: { name: "Number" } }, - metrics: { - serializedName: "metrics", - required: true, + errors: { + serializedName: "errors", type: { name: "Sequence", - element: { type: { name: "Composite", className: "MetricDataPoint" } } - } - }, - properties: { - serializedName: "properties", - type: { - name: "Dictionary", - value: { type: { name: "String" }, constraints: { MaxLength: 8192 } } + element: { + type: { name: "Composite", className: "TelemetryErrorDetails" } + } } } } } }; -export const PageViewData: coreHttp.CompositeMapper = { +export const TelemetryErrorDetails: coreHttp.CompositeMapper = { type: { name: "Composite", - className: "PageViewData", + className: "TelemetryErrorDetails", modelProperties: { - ...MonitorDomain.type.modelProperties, - version: { - defaultValue: 2, - serializedName: "ver", - required: true, + index: { + serializedName: "index", type: { name: "Number" } }, - id: { - constraints: { - MaxLength: 512 - }, - serializedName: "id", - required: true, - type: { - name: "String" - } - }, - name: { - constraints: { - MaxLength: 1024 - }, - serializedName: "name", - required: true, - type: { - name: "String" - } - }, - url: { - constraints: { - MaxLength: 2048 - }, - serializedName: "url", - type: { - name: "String" - } - }, - duration: { - serializedName: "duration", - type: { - name: "String" - } - }, - referredUri: { - constraints: { - MaxLength: 2048 - }, - serializedName: "referredUri", - type: { - name: "String" - } - }, - properties: { - serializedName: "properties", - type: { - name: "Dictionary", - value: { type: { name: "String" }, constraints: { MaxLength: 8192 } } - } - }, - measurements: { - serializedName: "measurements", - type: { - name: "Dictionary", - value: { type: { name: "Number" } } - } - } - } - } -}; - -export const PageViewPerfData: coreHttp.CompositeMapper = { - type: { - name: "Composite", - className: "PageViewPerfData", - modelProperties: { - ...MonitorDomain.type.modelProperties, - version: { - defaultValue: 2, - serializedName: "ver", - required: true, + statusCode: { + serializedName: "statusCode", type: { name: "Number" } }, - id: { - constraints: { - MaxLength: 512 - }, - serializedName: "id", - required: true, - type: { - name: "String" - } - }, - name: { - constraints: { - MaxLength: 1024 - }, - serializedName: "name", - required: true, - type: { - name: "String" - } - }, - url: { - constraints: { - MaxLength: 2048 - }, - serializedName: "url", - type: { - name: "String" - } - }, - duration: { - serializedName: "duration", - type: { - name: "String" - } - }, - perfTotal: { - serializedName: "perfTotal", - type: { - name: "String" - } - }, - networkConnect: { - serializedName: "networkConnect", - type: { - name: "String" - } - }, - sentRequest: { - serializedName: "sentRequest", - type: { - name: "String" - } - }, - receivedResponse: { - serializedName: "receivedResponse", - type: { - name: "String" - } - }, - domProcessing: { - serializedName: "domProcessing", + message: { + serializedName: "message", type: { name: "String" } - }, - properties: { - serializedName: "properties", - type: { - name: "Dictionary", - value: { type: { name: "String" }, constraints: { MaxLength: 8192 } } - } - }, - measurements: { - serializedName: "measurements", - type: { - name: "Dictionary", - value: { type: { name: "Number" } } - } } } } }; export const RemoteDependencyData: coreHttp.CompositeMapper = { + serializedName: "RemoteDependencyData", type: { name: "Composite", className: "RemoteDependencyData", + uberParent: "MonitorDomain", + polymorphicDiscriminator: MonitorDomain.type.polymorphicDiscriminator, modelProperties: { ...MonitorDomain.type.modelProperties, - version: { - defaultValue: 2, - serializedName: "ver", - required: true, - type: { - name: "Number" - } - }, id: { constraints: { MaxLength: 512 @@ -884,19 +279,14 @@ export const RemoteDependencyData: coreHttp.CompositeMapper = { }; export const RequestData: coreHttp.CompositeMapper = { + serializedName: "RequestData", type: { name: "Composite", className: "RequestData", + uberParent: "MonitorDomain", + polymorphicDiscriminator: MonitorDomain.type.polymorphicDiscriminator, modelProperties: { ...MonitorDomain.type.modelProperties, - version: { - defaultValue: 2, - serializedName: "ver", - required: true, - type: { - name: "Number" - } - }, id: { constraints: { MaxLength: 512 @@ -976,3 +366,9 @@ export const RequestData: coreHttp.CompositeMapper = { } } }; + +export let discriminators = { + MonitorDomain: MonitorDomain, + "MonitorDomain.RemoteDependencyData": RemoteDependencyData, + "MonitorDomain.RequestData": RequestData +}; diff --git a/sdk/monitor/monitor-opentelemetry-exporter/src/utils/spanUtils.ts b/sdk/monitor/monitor-opentelemetry-exporter/src/utils/spanUtils.ts index e04de75f392f..1179908548ad 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/src/utils/spanUtils.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/src/utils/spanUtils.ts @@ -86,6 +86,7 @@ function createPropertiesFromSpan(span: ReadableSpan): [Properties, Measurements function createDependencyData(span: ReadableSpan): RemoteDependencyData { const data: RemoteDependencyData = { + typename: "RemoteDependencyData", name: span.name, id: `|${span.spanContext.traceId}.${span.spanContext.spanId}.`, success: span.status.code === CanonicalCode.OK, @@ -140,6 +141,7 @@ function createDependencyData(span: ReadableSpan): RemoteDependencyData { function createRequestData(span: ReadableSpan): RequestData { const data: RequestData = { + typename: "RequestData", name: span.name, id: `|${span.spanContext.traceId}.${span.spanContext.spanId}.`, success: span.status.code === CanonicalCode.OK, @@ -224,9 +226,12 @@ export function readableSpanToEnvelope( throw new Error(`Unsupported span kind ${span.kind}`); } - envelope.data.baseData = { ...data, properties, measurements } as - | RequestData - | RemoteDependencyData; + envelope.data.baseData = { + ...data, + typename: envelope.data.baseType, + properties, + measurements + } as RequestData | RemoteDependencyData; envelope.tags = tags; envelope.time = new Date(hrTimeToMilliseconds(span.startTime)); envelope.instrumentationKey = instrumentationKey; diff --git a/sdk/monitor/monitor-opentelemetry-exporter/swagger/README.md b/sdk/monitor/monitor-opentelemetry-exporter/swagger/README.md index aa548ba771e4..8d34ecae7525 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/swagger/README.md +++ b/sdk/monitor/monitor-opentelemetry-exporter/swagger/README.md @@ -21,7 +21,8 @@ generate-metadata: false license-header: MICROSOFT_MIT_NO_VERSION output-folder: ../ source-code-folder-path: ./src/generated -input-file: https://github.com/srnagar/swagger/blob/master/application-insights.json +input-file: ./swagger.json +# input-file: https://github.com/srnagar/swagger/blob/master/application-insights.json add-credentials: false use-extension: "@autorest/typescript": "6.0.0-dev.20200826.1" diff --git a/sdk/monitor/monitor-opentelemetry-exporter/swagger/swagger.json b/sdk/monitor/monitor-opentelemetry-exporter/swagger/swagger.json new file mode 100644 index 000000000000..9c10ecf480f9 --- /dev/null +++ b/sdk/monitor/monitor-opentelemetry-exporter/swagger/swagger.json @@ -0,0 +1,512 @@ +{ + "swagger": "2.0", + "info": { + "version": "2020-09-15_Preview", + "title": "ApplicationInsightsClient", + "description": "This document describes the protocol for client requests and responses to the data collection endpoint." + }, + "x-ms-parameterized-host": { + "hostTemplate": "{Host}/v2/", + "useSchemePrefix": false, + "parameters": [ + { + "$ref": "#/parameters/Host" + } + ] + }, + "paths": { + "/track": { + "post": { + "summary": "Detect anomalies for the entire series in batch.", + "description": "This operation generates a model using an entire series, each point is detected with the same model. With this method, points before and after a certain point are used to determine whether it is an anomaly. The entire detection can give user an overall status of the time series.", + "operationId": "track", + "parameters": [ + { + "name": "body", + "in": "body", + "description": "Time series points and period if needed. Advanced model parameters can also be set in the request.", + "required": true, + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/TelemetryEnvelope" + } + } + } + ], + "consumes": [ + "application/json", + "x-json-stream" + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "All of the telemetry items were accepted and processed.", + "schema": { + "$ref": "#/definitions/TrackResponse" + } + }, + "206": { + "description": "Partial success. Some of the telemetry items were accepted and processed.", + "schema": { + "$ref": "#/definitions/TrackResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/TrackResponse" + } + }, + "402": { + "description": "Payment Required", + "schema": { + "$ref": "#/definitions/TrackResponse" + } + }, + "429": { + "description": "Too Many Requests", + "schema": { + "$ref": "#/definitions/TrackResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/TrackResponse" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/TrackResponse" + } + } + }, + "x-ms-examples": { + "Track examples": { + "$ref": ".//examples//track.json" + } + } + } + } + }, + "definitions": { + "Base": { + "x-ms-client-name": "MonitorBase", + "type": "object", + "description": "Data struct to contain only C section with custom fields.", + "properties": { + "baseType": { + "type": "string", + "description": "Name of item (B section) if any. If telemetry data is derived straight from this, this should be null." + }, + "baseData": { + "additionalProperties": true, + "$ref": "#/definitions/Domain", + "description": "The data payload for the telemetry request" + } + } + }, + "Domain": { + "x-ms-client-name": "MonitorDomain", + "type": "object", + "description": "The abstract common base of all domains.", + "discriminator": "typename", + "required": [ + "typename", + "ver" + ], + "properties": { + "ver": { + "x-ms-client-name": "version", + "type": "integer", + "format": "int32", + "description": "Schema version", + "default": 2 + }, + "typename": { + "type": "string" + } + } + }, + "RemoteDependencyData": { + "allOf": [ + { + "$ref": "#/definitions/Domain" + }, + { + "type": "object", + "description": "An instance of Remote Dependency represents an interaction of the monitored component with a remote component/service like SQL or an HTTP endpoint.", + "required": [ + "name", + "duration" + ], + "properties": { + "id": { + "type": "string", + "description": "Identifier of a dependency call instance. Used for correlation with the request telemetry item corresponding to this dependency call.", + "maxLength": 512 + }, + "name": { + "type": "string", + "description": "Name of the command initiated with this dependency call. Low cardinality value. Examples are stored procedure name and URL path template.", + "maxLength": 1024 + }, + "resultCode": { + "type": "string", + "description": "Result code of a dependency call. Examples are SQL error code and HTTP status code.", + "maxLength": 1024 + }, + "data": { + "type": "string", + "description": "Command initiated by this dependency call. Examples are SQL statement and HTTP URL with all query parameters.", + "maxLength": 8192 + }, + "type": { + "type": "string", + "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.", + "maxLength": 1024 + }, + "target": { + "type": "string", + "description": "Target site of a dependency call. Examples are server name, host address.", + "maxLength": 1024 + }, + "duration": { + "type": "string", + "description": "Request duration in format: DD.HH:MM:SS.MMMMMM. Must be less than 1000 days." + }, + "success": { + "type": "boolean", + "description": "Indication of successful or unsuccessful call.", + "default": true + }, + "properties": { + "type": "object", + "description": "Collection of custom properties.", + "additionalProperties": { + "type": "string", + "maxLength": 8192 + } + }, + "measurements": { + "type": "object", + "description": "Collection of custom measurements.", + "additionalProperties": { + "type": "number", + "format": "double" + } + } + } + } + ] + }, + "RequestData": { + "allOf": [ + { + "$ref": "#/definitions/Domain" + }, + { + "type": "object", + "description": "An instance of PageView represents a generic action on a page like a button click. It is also the base type for PageView.", + "required": [ + "id", + "duration", + "responseCode", + "success" + ], + "properties": { + "id": { + "type": "string", + "description": "Identifier of a request call instance. Used for correlation between request and other telemetry items.", + "maxLength": 512 + }, + "name": { + "type": "string", + "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}'.", + "maxLength": 1024 + }, + "duration": { + "type": "string", + "description": "Request duration in format: DD.HH:MM:SS.MMMMMM. Must be less than 1000 days." + }, + "success": { + "type": "boolean", + "description": "Indication of successful or unsuccessful call.", + "default": true + }, + "responseCode": { + "type": "string", + "description": "Result of a request execution. HTTP status code for HTTP requests.", + "maxLength": 1024 + }, + "source": { + "type": "string", + "description": "Source of the request. Examples are the instrumentation key of the caller or the ip address of the caller.", + "maxLength": 1024 + }, + "url": { + "type": "string", + "description": "Request URL with all query string parameters.", + "maxLength": 2048 + }, + "properties": { + "type": "object", + "description": "Collection of custom properties.", + "additionalProperties": { + "type": "string", + "maxLength": 8192 + } + }, + "measurements": { + "type": "object", + "description": "Collection of custom measurements.", + "additionalProperties": { + "type": "number", + "format": "double" + } + } + } + } + ] + }, + "TrackResponse": { + "description": "Response containing the status of each telemetry item.", + "type": "object", + "properties": { + "itemsReceived": { + "type": "number", + "format": "int32", + "description": "The number of items received." + }, + "itemsAccepted": { + "type": "number", + "format": "int32", + "description": "The number of items accepted." + }, + "errors": { + "type": "array", + "description": "An array of error detail objects.", + "items": { + "$ref": "#/definitions/ErrorDetails" + } + } + } + }, + "ErrorDetails": { + "x-ms-client-name": "TelemetryErrorDetails", + "description": "The error details", + "type": "object", + "properties": { + "index": { + "type": "number", + "format": "int32", + "description": "The index in the original payload of the item." + }, + "statusCode": { + "type": "number", + "format": "int32", + "description": "The item specific [HTTP Response status code](#Response Status Codes)." + }, + "message": { + "type": "string", + "description": "The error message." + } + } + }, + "TelemetryEnvelope": { + "x-ms-client-name": "TelemetryItem", + "description": "System variables for a telemetry item.", + "type": "object", + "required": [ + "name", + "time" + ], + "properties": { + "ver": { + "type": "number", + "x-ms-client-name": "version", + "format": "int32", + "default": 1, + "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": { + "type": "string", + "description": "Type name of telemetry data item." + }, + "time": { + "type": "string", + "format": "date-time", + "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." + }, + "sampleRate": { + "type": "number", + "format": "float", + "default": 100.0, + "description": "Sampling rate used in application. This telemetry item represents 1 / sampleRate actual telemetry items." + }, + "seq": { + "type": "string", + "x-ms-client-name": "sequence", + "maxLength": 64, + "description": "Sequence field used to track absolute order of uploaded events." + }, + "iKey": { + "type": "string", + "x-ms-client-name": "instrumentationKey", + "description": "The instrumentation key of the Application Insights resource." + }, + "tags": { + "type": "object", + "description": "Key/value collection of context properties. See ContextTagKeys for information on available properties.", + "additionalProperties": { + "type": "string" + } + }, + "data": { + "$ref": "#/definitions/Base", + "description": "Telemetry data item." + } + } + }, + "ContextTagKeys": { + "type": "string", + "description": "The context tag keys.", + "enum": [ + "ApplicationVersion", + "DeviceId", + "DeviceLocale", + "DeviceModel", + "DeviceOEMName", + "DeviceOSVersion", + "DeviceType", + "LocationIp", + "LocationCountry", + "LocationProvince", + "LocationCity", + "OperationId", + "OperationName", + "OperationParentId", + "OperationSyntheticSource", + "OperationCorrelationVector", + "SessionId", + "SessionIsFirst", + "UserAccountId", + "UserId", + "UserAuthUserId", + "CloudRole", + "CloudRoleVer", + "CloudRoleInstance", + "CloudLocation", + "InternalSdkVersion", + "InternalAgentVersion", + "InternalNodeName " + ], + "x-ms-enum": { + "name": "ContextTagKeys", + "modelAsString": true, + "values": [ + { + "value": "ai.application.ver" + }, + { + "value": "ai.device.id" + }, + { + "value": "ai.device.locale" + }, + { + "value": "ai.device.model" + }, + { + "value": "ai.device.oemName" + }, + { + "value": "ai.device.osVersion" + }, + { + "value": "ai.device.type" + }, + { + "value": "ai.location.ip" + }, + { + "value": "ai.location.country" + }, + { + "value": "ai.location.province" + }, + { + "value": "ai.location.city" + }, + { + "value": "ai.operation.id" + }, + { + "value": "ai.operation.name" + }, + { + "value": "ai.operation.parentId" + }, + { + "value": "ai.operation.syntheticSource" + }, + { + "value": "ai.operation.correlationVector" + }, + { + "value": "ai.session.id" + }, + { + "value": "ai.session.isFirst" + }, + { + "value": "ai.user.accountId" + }, + { + "value": "ai.user.id" + }, + { + "value": "ai.user.authUserId" + }, + { + "value": "ai.cloud.role" + }, + { + "value": "ai.cloud.roleVer" + }, + { + "value": "ai.cloud.roleInstance" + }, + { + "value": "ai.cloud.location" + }, + { + "value": "ai.internal.sdkVersion" + }, + { + "value": "ai.internal.agentVersion" + }, + { + "value": "ai.internal.nodeName" + } + ] + } + } + }, + "parameters": { + "Host": { + "name": "Host", + "description": "Breeze endpoint: https://dc.services.visualstudio.com", + "x-ms-parameter-location": "client", + "default": "https://dc.services.visualstudio.com", + "required": true, + "type": "string", + "in": "path", + "x-ms-skip-url-encoding": true + } + } +} \ No newline at end of file diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/common/scenario/basic.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/common/scenario/basic.ts index 19c04b2d4fb5..c72258e49ec1 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/common/scenario/basic.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/common/scenario/basic.ts @@ -9,11 +9,7 @@ import { msToTimeSpan } from "../../../src/utils/breezeUtils"; import { CanonicalCode } from "@opentelemetry/api"; import { FlushSpanProcessor } from "../flushSpanProcessor"; import { delay } from "@azure/core-http"; -import { - TelemetryItem as Envelope, - RemoteDependencyData, - RequestData -} from "../../../src/generated"; +import { TelemetryItem as Envelope } from "../../../src/generated"; const COMMON_ENVELOPE_PARAMS: Partial = { instrumentationKey: process.env.APPINSIGHTS_INSTRUMENTATIONKEY || "ikey", @@ -96,7 +92,7 @@ export class BasicScenario implements Scenario { properties: { foo: "bar" } - } as Omit + } as any }, children: [ { @@ -112,7 +108,7 @@ export class BasicScenario implements Scenario { properties: { numbers: 123 as any } - } as Omit + } as any }, children: [] }, @@ -129,7 +125,7 @@ export class BasicScenario implements Scenario { properties: { numbers: 1234 as any } - } as Omit + } as any }, children: [] } diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/functional/trace.test.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/functional/trace.test.ts index b189bb7514d1..6843fd8a9e32 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/functional/trace.test.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/functional/trace.test.ts @@ -18,6 +18,7 @@ describe("Trace Exporter Scenarios", () => { // todo: gzip is not supported by generated applicationInsightsClient // const buffer = gunzipSync(Buffer.from(body, "hex")); // ingest.push(...(JSON.parse(buffer.toString("utf8")) as Envelope[])); + console.log(body[0].data?.baseData); ingest.push(...body); return true; }) diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/spanUtils.test.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/spanUtils.test.ts index 974a6a9187bf..15caa2574d3c 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/spanUtils.test.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/spanUtils.test.ts @@ -305,6 +305,7 @@ describe("spanUtils.ts", () => { }; const expectedBaseData: RequestData = { + typename: "RequestData", duration: msToTimeSpan(hrTimeToMilliseconds(span.duration)), id: `|${span.spanContext.traceId}.${span.spanContext.spanId}.`, success: true, @@ -355,6 +356,7 @@ describe("spanUtils.ts", () => { }; const expectedBaseData: RemoteDependencyData = { + typename: "RemoteDependencyData", duration: msToTimeSpan(hrTimeToMilliseconds(span.duration)), id: `|traceid.spanId.`, success: true, From 0cfe50093a44505eabe23ef361ad9defcfef5514 Mon Sep 17 00:00:00 2001 From: Mark Wolff Date: Tue, 22 Sep 2020 16:50:13 -0700 Subject: [PATCH 07/13] swagger styling --- .../swagger/swagger.json | 33 ++++--------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/sdk/monitor/monitor-opentelemetry-exporter/swagger/swagger.json b/sdk/monitor/monitor-opentelemetry-exporter/swagger/swagger.json index 9c10ecf480f9..8569e8626f11 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/swagger/swagger.json +++ b/sdk/monitor/monitor-opentelemetry-exporter/swagger/swagger.json @@ -34,13 +34,8 @@ } } ], - "consumes": [ - "application/json", - "x-json-stream" - ], - "produces": [ - "application/json" - ], + "consumes": ["application/json", "x-json-stream"], + "produces": ["application/json"], "responses": { "200": { "description": "All of the telemetry items were accepted and processed.", @@ -115,10 +110,7 @@ "type": "object", "description": "The abstract common base of all domains.", "discriminator": "typename", - "required": [ - "typename", - "ver" - ], + "required": ["typename", "ver"], "properties": { "ver": { "x-ms-client-name": "version", @@ -140,10 +132,7 @@ { "type": "object", "description": "An instance of Remote Dependency represents an interaction of the monitored component with a remote component/service like SQL or an HTTP endpoint.", - "required": [ - "name", - "duration" - ], + "required": ["name", "duration"], "properties": { "id": { "type": "string", @@ -212,12 +201,7 @@ { "type": "object", "description": "An instance of PageView represents a generic action on a page like a button click. It is also the base type for PageView.", - "required": [ - "id", - "duration", - "responseCode", - "success" - ], + "required": ["id", "duration", "responseCode", "success"], "properties": { "id": { "type": "string", @@ -321,10 +305,7 @@ "x-ms-client-name": "TelemetryItem", "description": "System variables for a telemetry item.", "type": "object", - "required": [ - "name", - "time" - ], + "required": ["name", "time"], "properties": { "ver": { "type": "number", @@ -509,4 +490,4 @@ "x-ms-skip-url-encoding": true } } -} \ No newline at end of file +} From c461b7a80d61ac40e14d898db55fe05fed72134e Mon Sep 17 00:00:00 2001 From: Mark Wolff Date: Tue, 22 Sep 2020 20:47:56 -0700 Subject: [PATCH 08/13] try RequestTelemetry schema --- .../generated/applicationInsightsClient.ts | 7 +- .../src/generated/models/index.ts | 217 ++++++++-- .../src/generated/models/mappers.ts | 370 +++++++++++++++--- .../src/utils/spanUtils.ts | 13 +- .../swagger/swagger.json | 242 +++++++++++- .../test/common/assert.ts | 7 +- .../test/common/scenario/basic.ts | 8 +- .../test/functional/trace.test.ts | 1 - .../test/unit/utils/spanUtils.test.ts | 2 - 9 files changed, 739 insertions(+), 128 deletions(-) diff --git a/sdk/monitor/monitor-opentelemetry-exporter/src/generated/applicationInsightsClient.ts b/sdk/monitor/monitor-opentelemetry-exporter/src/generated/applicationInsightsClient.ts index adc482835895..33dea89acc02 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/src/generated/applicationInsightsClient.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/src/generated/applicationInsightsClient.ts @@ -26,11 +26,8 @@ export class ApplicationInsightsClient extends ApplicationInsightsClientContext } /** - * This operation generates a model using an entire series, each point is detected with the same model. - * With this method, points before and after a certain point are used to determine whether it is an - * anomaly. The entire detection can give user an overall status of the time series. - * @param body Time series points and period if needed. Advanced model parameters can also be set in - * the request. + * This operation sends a sequence of telemetry events that will be monitored by Azure Monitor. + * @param body The list of telemetry events to track. * @param options The options parameters. */ track( diff --git a/sdk/monitor/monitor-opentelemetry-exporter/src/generated/models/index.ts b/sdk/monitor/monitor-opentelemetry-exporter/src/generated/models/index.ts index 6cd3bd71b189..6bae7baa66c1 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/src/generated/models/index.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/src/generated/models/index.ts @@ -8,10 +8,10 @@ import * as coreHttp from "@azure/core-http"; -export type MonitorDomainUnion = - | MonitorDomain - | RemoteDependencyData - | RequestData; +export type MonitorBaseUnion = + | MonitorBase + | RequestTelemetry + | RemoteDependencyTelememetry; /** * System variables for a telemetry item. @@ -48,35 +48,21 @@ export interface TelemetryItem { /** * Telemetry data item. */ - data?: MonitorBase; + data?: MonitorBaseUnion; } /** * Data struct to contain only C section with custom fields. */ export interface MonitorBase { - /** - * Name of item (B section) if any. If telemetry data is derived straight from this, this should be null. - */ - baseType?: string; - /** - * The data payload for the telemetry request - */ - baseData?: MonitorDomainUnion; -} - -/** - * The abstract common base of all domains. - */ -export interface MonitorDomain { /** * Polymorphic discriminator, which specifies the different types this object can be */ - typename: "RemoteDependencyData" | "RequestData"; + baseType: "RequestData" | "RemoteDependencyData"; /** - * Schema version + * Describes unknown properties. The value of an unknown property can be of "any" type. */ - version: number; + [property: string]: any; } /** @@ -116,41 +102,118 @@ export interface TelemetryErrorDetails { } /** - * An instance of Remote Dependency represents an interaction of the monitored component with a remote component/service like SQL or an HTTP endpoint. + * The abstract common base of all domains. */ -export type RemoteDependencyData = MonitorDomain & { +export interface MonitorDomain { /** - * Identifier of a dependency call instance. Used for correlation with the request telemetry item corresponding to this dependency call. + * Schema version */ - id?: string; + version: number; +} + +/** + * Metric data single measurement. + */ +export interface MetricDataPoint { /** - * Name of the command initiated with this dependency call. Low cardinality value. Examples are stored procedure name and URL path template. + * Namespace of the metric. + */ + namespace?: string; + /** + * Name of the metric. */ name: string; /** - * Result code of a dependency call. Examples are SQL error code and HTTP status code. + * Metric type. Single measurement or the aggregated value. */ - resultCode?: string; + dataPointType?: DataPointType; /** - * Command initiated by this dependency call. Examples are SQL statement and HTTP URL with all query parameters. + * Single value for measurement. Sum of individual measurements for the aggregation. */ - data?: string; + value: number; /** - * 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. + * Metric weight of the aggregated metric. Should not be set for a measurement. */ - type?: string; + count?: number; /** - * Target site of a dependency call. Examples are server name, host address. + * Minimum value of the aggregated metric. Should not be set for a measurement. */ - target?: string; + min?: number; /** - * Request duration in format: DD.HH:MM:SS.MMMMMM. Must be less than 1000 days. + * Maximum value of the aggregated metric. Should not be set for a measurement. + */ + max?: number; + /** + * Standard deviation of the aggregated metric. Should not be set for a measurement. + */ + stdDev?: number; +} + +/** + * Stack frame information. + */ +export interface StackFrame { + level: number; + /** + * Method name. + */ + method: string; + /** + * Name of the assembly (dll, jar, etc.) containing this function. + */ + assembly?: string; + /** + * File name or URL of the method implementation. + */ + fileName?: string; + /** + * Line number of the code implementation. + */ + line?: number; +} + +export type RequestTelemetry = MonitorBase & { + /** + * An instance of PageView represents a generic action on a page like a button click. It is also the base type for PageView. + */ + baseData: RequestData; +}; + +export type RemoteDependencyTelememetry = MonitorBase & { + /** + * An instance of Remote Dependency represents an interaction of the monitored component with a remote component/service like SQL or an HTTP endpoint. + */ + baseData: RemoteDependencyData; +}; + +/** + * Instances of AvailabilityData represent the result of executing an availability test. + */ +export type AvailabilityData = MonitorDomain & { + /** + * Identifier of a test run. Use it to correlate steps of test run and telemetry generated by the service. + */ + id: string; + /** + * Name of the test that these availability results represent. + */ + name: string; + /** + * Duration in format: DD.HH:MM:SS.MMMMMM. Must be less than 1000 days. */ duration: string; /** - * Indication of successful or unsuccessful call. + * Success flag. */ - success?: boolean; + success: boolean; + /** + * Name of the location where the test was run from. + */ + runLocation?: string; + /** + * Diagnostic message for the result. + */ + message?: string; /** * Collection of custom properties. */ @@ -202,6 +265,84 @@ export type RequestData = MonitorDomain & { */ measurements?: { [propertyName: string]: number }; }; + +/** + * An instance of Remote Dependency represents an interaction of the monitored component with a remote component/service like SQL or an HTTP endpoint. + */ +export type RemoteDependencyData = MonitorDomain & { + /** + * Identifier of a dependency call instance. Used for correlation with the request telemetry item corresponding to this dependency call. + */ + id?: string; + /** + * Name of the command initiated with this dependency call. Low cardinality value. Examples are stored procedure name and URL path template. + */ + name: string; + /** + * Result code of a dependency call. Examples are SQL error code and HTTP status code. + */ + resultCode?: string; + /** + * Command initiated by this dependency call. Examples are SQL statement and HTTP URL with all query parameters. + */ + data?: string; + /** + * 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. + */ + type?: string; + /** + * Target site of a dependency call. Examples are server name, host address. + */ + target?: string; + /** + * Request duration in format: DD.HH:MM:SS.MMMMMM. Must be less than 1000 days. + */ + duration: string; + /** + * Indication of successful or unsuccessful call. + */ + success?: boolean; + /** + * Collection of custom properties. + */ + properties?: { [propertyName: string]: string }; + /** + * Collection of custom measurements. + */ + measurements?: { [propertyName: string]: number }; +}; + +/** + * 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. + */ +export type TelemetryEventData = MonitorDomain & { + /** + * Event name. Keep it low cardinality to allow proper grouping and useful metrics. + */ + name: string; + /** + * Collection of custom properties. + */ + properties?: { [propertyName: string]: string }; + /** + * Collection of custom measurements. + */ + measurements?: { [propertyName: string]: number }; +}; +/** + * Defines values for DataPointType. + */ +export type DataPointType = "Measurement" | "Aggregation" | string; +/** + * Defines values for SeverityLevel. + */ +export type SeverityLevel = + | "Verbose" + | "Information" + | "Warning" + | "Error" + | "Critical" + | string; /** * Defines values for ContextTagKeys. */ diff --git a/sdk/monitor/monitor-opentelemetry-exporter/src/generated/models/mappers.ts b/sdk/monitor/monitor-opentelemetry-exporter/src/generated/models/mappers.ts index 4cd4b1da50ec..fa957b7947f7 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/src/generated/models/mappers.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/src/generated/models/mappers.ts @@ -75,47 +75,19 @@ export const TelemetryItem: coreHttp.CompositeMapper = { }; export const MonitorBase: coreHttp.CompositeMapper = { + serializedName: "MonitorBase", type: { name: "Composite", className: "MonitorBase", - modelProperties: { - baseType: { - serializedName: "baseType", - type: { - name: "String" - } - }, - baseData: { - serializedName: "baseData", - type: { - name: "Composite", - className: "MonitorDomain" - } - } - } - } -}; - -export const MonitorDomain: coreHttp.CompositeMapper = { - type: { - name: "Composite", - className: "MonitorDomain", - uberParent: "MonitorDomain", + uberParent: "MonitorBase", + additionalProperties: { type: { name: "Object" } }, polymorphicDiscriminator: { - serializedName: "typename", - clientName: "typename" + serializedName: "baseType", + clientName: "baseType" }, modelProperties: { - version: { - defaultValue: 2, - serializedName: "ver", - required: true, - type: { - name: "Number" - } - }, - typename: { - serializedName: "typename", + baseType: { + serializedName: "baseType", required: true, type: { name: "String" @@ -182,20 +154,33 @@ export const TelemetryErrorDetails: coreHttp.CompositeMapper = { } }; -export const RemoteDependencyData: coreHttp.CompositeMapper = { - serializedName: "RemoteDependencyData", +export const MonitorDomain: coreHttp.CompositeMapper = { type: { name: "Composite", - className: "RemoteDependencyData", - uberParent: "MonitorDomain", - polymorphicDiscriminator: MonitorDomain.type.polymorphicDiscriminator, + className: "MonitorDomain", modelProperties: { - ...MonitorDomain.type.modelProperties, - id: { + version: { + defaultValue: 2, + serializedName: "ver", + required: true, + type: { + name: "Number" + } + } + } + } +}; + +export const MetricDataPoint: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "MetricDataPoint", + modelProperties: { + namespace: { constraints: { - MaxLength: 512 + MaxLength: 256 }, - serializedName: "id", + serializedName: "ns", type: { name: "String" } @@ -210,38 +195,161 @@ export const RemoteDependencyData: coreHttp.CompositeMapper = { name: "String" } }, - resultCode: { + dataPointType: { + serializedName: "kind", + type: { + name: "String" + } + }, + value: { + serializedName: "value", + required: true, + type: { + name: "Number" + } + }, + count: { + serializedName: "count", + type: { + name: "Number" + } + }, + min: { + serializedName: "min", + type: { + name: "Number" + } + }, + max: { + serializedName: "max", + type: { + name: "Number" + } + }, + stdDev: { + serializedName: "stdDev", + type: { + name: "Number" + } + } + } + } +}; + +export const StackFrame: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "StackFrame", + modelProperties: { + level: { + serializedName: "level", + required: true, + type: { + name: "Number" + } + }, + method: { constraints: { MaxLength: 1024 }, - serializedName: "resultCode", + serializedName: "method", + required: true, type: { name: "String" } }, - data: { + assembly: { constraints: { - MaxLength: 8192 + MaxLength: 1024 }, - serializedName: "data", + serializedName: "assembly", type: { name: "String" } }, - type: { + fileName: { constraints: { MaxLength: 1024 }, - serializedName: "type", + serializedName: "fileName", type: { name: "String" } }, - target: { + line: { + serializedName: "line", + type: { + name: "Number" + } + } + } + } +}; + +export const RequestTelemetry: coreHttp.CompositeMapper = { + serializedName: "RequestData", + type: { + name: "Composite", + className: "RequestTelemetry", + uberParent: "MonitorBase", + additionalProperties: { type: { name: "Object" } }, + polymorphicDiscriminator: MonitorBase.type.polymorphicDiscriminator, + modelProperties: { + ...MonitorBase.type.modelProperties, + baseData: { + serializedName: "baseData", + type: { + name: "Composite", + className: "RequestData" + } + } + } + } +}; + +export const RemoteDependencyTelememetry: coreHttp.CompositeMapper = { + serializedName: "RemoteDependencyData", + type: { + name: "Composite", + className: "RemoteDependencyTelememetry", + uberParent: "MonitorBase", + additionalProperties: { type: { name: "Object" } }, + polymorphicDiscriminator: MonitorBase.type.polymorphicDiscriminator, + modelProperties: { + ...MonitorBase.type.modelProperties, + baseData: { + serializedName: "baseData", + type: { + name: "Composite", + className: "RemoteDependencyData" + } + } + } + } +}; + +export const AvailabilityData: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "AvailabilityData", + modelProperties: { + ...MonitorDomain.type.modelProperties, + id: { + constraints: { + MaxLength: 512 + }, + serializedName: "id", + required: true, + type: { + name: "String" + } + }, + name: { constraints: { MaxLength: 1024 }, - serializedName: "target", + serializedName: "name", + required: true, type: { name: "String" } @@ -254,12 +362,30 @@ export const RemoteDependencyData: coreHttp.CompositeMapper = { } }, success: { - defaultValue: true, serializedName: "success", + required: true, type: { name: "Boolean" } }, + runLocation: { + constraints: { + MaxLength: 1024 + }, + serializedName: "runLocation", + type: { + name: "String" + } + }, + message: { + constraints: { + MaxLength: 8192 + }, + serializedName: "message", + type: { + name: "String" + } + }, properties: { serializedName: "properties", type: { @@ -279,12 +405,9 @@ export const RemoteDependencyData: coreHttp.CompositeMapper = { }; export const RequestData: coreHttp.CompositeMapper = { - serializedName: "RequestData", type: { name: "Composite", className: "RequestData", - uberParent: "MonitorDomain", - polymorphicDiscriminator: MonitorDomain.type.polymorphicDiscriminator, modelProperties: { ...MonitorDomain.type.modelProperties, id: { @@ -367,8 +490,135 @@ export const RequestData: coreHttp.CompositeMapper = { } }; +export const RemoteDependencyData: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "RemoteDependencyData", + modelProperties: { + ...MonitorDomain.type.modelProperties, + id: { + constraints: { + MaxLength: 512 + }, + serializedName: "id", + type: { + name: "String" + } + }, + name: { + constraints: { + MaxLength: 1024 + }, + serializedName: "name", + required: true, + type: { + name: "String" + } + }, + resultCode: { + constraints: { + MaxLength: 1024 + }, + serializedName: "resultCode", + type: { + name: "String" + } + }, + data: { + constraints: { + MaxLength: 8192 + }, + serializedName: "data", + type: { + name: "String" + } + }, + type: { + constraints: { + MaxLength: 1024 + }, + serializedName: "type", + type: { + name: "String" + } + }, + target: { + constraints: { + MaxLength: 1024 + }, + serializedName: "target", + type: { + name: "String" + } + }, + duration: { + serializedName: "duration", + required: true, + type: { + name: "String" + } + }, + success: { + defaultValue: true, + serializedName: "success", + type: { + name: "Boolean" + } + }, + properties: { + serializedName: "properties", + type: { + name: "Dictionary", + value: { type: { name: "String" }, constraints: { MaxLength: 8192 } } + } + }, + measurements: { + serializedName: "measurements", + type: { + name: "Dictionary", + value: { type: { name: "Number" } } + } + } + } + } +}; + +export const TelemetryEventData: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "TelemetryEventData", + modelProperties: { + ...MonitorDomain.type.modelProperties, + name: { + constraints: { + MaxLength: 512 + }, + serializedName: "name", + required: true, + type: { + name: "String" + } + }, + properties: { + serializedName: "properties", + type: { + name: "Dictionary", + value: { type: { name: "String" }, constraints: { MaxLength: 8192 } } + } + }, + measurements: { + serializedName: "measurements", + type: { + name: "Dictionary", + value: { type: { name: "Number" } } + } + } + } + } +}; + export let discriminators = { - MonitorDomain: MonitorDomain, - "MonitorDomain.RemoteDependencyData": RemoteDependencyData, - "MonitorDomain.RequestData": RequestData + MonitorBase: MonitorBase, + "MonitorBase.RequestData": RequestTelemetry, + "MonitorBase.RemoteDependencyData": RemoteDependencyTelememetry }; diff --git a/sdk/monitor/monitor-opentelemetry-exporter/src/utils/spanUtils.ts b/sdk/monitor/monitor-opentelemetry-exporter/src/utils/spanUtils.ts index 1179908548ad..311f6af57105 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/src/utils/spanUtils.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/src/utils/spanUtils.ts @@ -30,7 +30,13 @@ import { getInstance } from "../platform"; import { DB_STATEMENT, DB_TYPE, DB_INSTANCE } from "./constants/span/dbAttributes"; import { parseEventHubSpan } from "./eventhub"; import { AzNamespace, MicrosoftEventHub } from "./constants/span/azAttributes"; -import { RemoteDependencyData, RequestData, TelemetryItem as Envelope } from "../generated"; +import { + RemoteDependencyData, + RemoteDependencyTelememetry, + RequestData, + RequestTelemetry, + TelemetryItem as Envelope +} from "../generated"; function createTagsFromSpan(span: ReadableSpan): Tags { const context = getInstance(); @@ -86,7 +92,6 @@ function createPropertiesFromSpan(span: ReadableSpan): [Properties, Measurements function createDependencyData(span: ReadableSpan): RemoteDependencyData { const data: RemoteDependencyData = { - typename: "RemoteDependencyData", name: span.name, id: `|${span.spanContext.traceId}.${span.spanContext.spanId}.`, success: span.status.code === CanonicalCode.OK, @@ -141,7 +146,6 @@ function createDependencyData(span: ReadableSpan): RemoteDependencyData { function createRequestData(span: ReadableSpan): RequestData { const data: RequestData = { - typename: "RequestData", name: span.name, id: `|${span.spanContext.traceId}.${span.spanContext.spanId}.`, success: span.status.code === CanonicalCode.OK, @@ -196,7 +200,7 @@ export function readableSpanToEnvelope( ): Envelope { const envelope: Partial = {}; envelope.sampleRate = 100; - envelope.data = {}; + envelope.data = {} as RemoteDependencyTelememetry | RequestTelemetry; const tags = createTagsFromSpan(span); const [properties, measurements] = createPropertiesFromSpan(span); let data; @@ -228,7 +232,6 @@ export function readableSpanToEnvelope( envelope.data.baseData = { ...data, - typename: envelope.data.baseType, properties, measurements } as RequestData | RemoteDependencyData; diff --git a/sdk/monitor/monitor-opentelemetry-exporter/swagger/swagger.json b/sdk/monitor/monitor-opentelemetry-exporter/swagger/swagger.json index 8569e8626f11..b9ad49a30ad9 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/swagger/swagger.json +++ b/sdk/monitor/monitor-opentelemetry-exporter/swagger/swagger.json @@ -17,14 +17,14 @@ "paths": { "/track": { "post": { - "summary": "Detect anomalies for the entire series in batch.", - "description": "This operation generates a model using an entire series, each point is detected with the same model. With this method, points before and after a certain point are used to determine whether it is an anomaly. The entire detection can give user an overall status of the time series.", + "summary": "Track telemetry events", + "description": "This operation sends a sequence of telemetry events that will be monitored by Azure Monitor.", "operationId": "track", "parameters": [ { "name": "body", "in": "body", - "description": "Time series points and period if needed. Advanced model parameters can also be set in the request.", + "description": "The list of telemetry events to track.", "required": true, "schema": { "type": "array", @@ -89,28 +89,176 @@ } }, "definitions": { + "AvailabilityData": { + "allOf": [ + { + "$ref": "#/definitions/Domain" + }, + { + "type": "object", + "description": "Instances of AvailabilityData represent the result of executing an availability test.", + "required": ["id", "name", "duration", "success"], + "properties": { + "id": { + "type": "string", + "description": "Identifier of a test run. Use it to correlate steps of test run and telemetry generated by the service.", + "maxLength": 512 + }, + "name": { + "type": "string", + "description": "Name of the test that these availability results represent.", + "maxLength": 1024 + }, + "duration": { + "type": "string", + "description": "Duration in format: DD.HH:MM:SS.MMMMMM. Must be less than 1000 days." + }, + "success": { + "type": "boolean", + "x-nullable": false, + "description": "Success flag." + }, + "runLocation": { + "type": "string", + "description": "Name of the location where the test was run from.", + "maxLength": 1024 + }, + "message": { + "type": "string", + "description": "Diagnostic message for the result.", + "maxLength": 8192 + }, + "properties": { + "type": "object", + "description": "Collection of custom properties.", + "additionalProperties": { + "type": "string", + "maxLength": 8192 + } + }, + "measurements": { + "type": "object", + "description": "Collection of custom measurements.", + "additionalProperties": { + "type": "number", + "format": "double" + } + } + } + } + ] + }, "Base": { "x-ms-client-name": "MonitorBase", "type": "object", "description": "Data struct to contain only C section with custom fields.", + "discriminator": "baseType", + "required": ["baseType", "baseData"], + "additionalProperties": true, "properties": { "baseType": { "type": "string", "description": "Name of item (B section) if any. If telemetry data is derived straight from this, this should be null." + } + } + }, + "RequestTelemetry": { + "x-ms-discriminator-value": "RequestData", + "required": ["baseType", "baseData"], + "allOf": [ + { + "$ref": "#/definitions/Base" }, - "baseData": { - "additionalProperties": true, - "$ref": "#/definitions/Domain", - "description": "The data payload for the telemetry request" + { + "type": "object", + "properties": { + "baseData": { + "$ref": "#/definitions/RequestData" + } + } + } + ] + }, + "RemoteDependencyTelememetry": { + "x-ms-discriminator-value": "RemoteDependencyData", + "required": ["baseType", "baseData"], + "allOf": [ + { + "$ref": "#/definitions/Base" + }, + { + "type": "object", + "properties": { + "baseData": { + "$ref": "#/definitions/RemoteDependencyData" + } + } + } + ] + }, + "DataPoint": { + "x-ms-client-name": "MetricDataPoint", + "type": "object", + "description": "Metric data single measurement.", + "required": ["name", "value"], + "properties": { + "ns": { + "x-ms-client-name": "namespace", + "type": "string", + "description": "Namespace of the metric.", + "maxLength": 256 + }, + "name": { + "type": "string", + "description": "Name of the metric.", + "maxLength": 1024 + }, + "kind": { + "x-ms-client-name": "dataPointType", + "$ref": "#/definitions/DataPointType", + "description": "Metric type. Single measurement or the aggregated value." + }, + "value": { + "type": "number", + "description": "Single value for measurement. Sum of individual measurements for the aggregation.", + "format": "double" + }, + "count": { + "type": "number", + "format": "int32", + "description": "Metric weight of the aggregated metric. Should not be set for a measurement.", + "x-nullable": true + }, + "min": { + "type": "number", + "format": "double", + "description": "Minimum value of the aggregated metric. Should not be set for a measurement.", + "x-nullable": true + }, + "max": { + "type": "number", + "format": "double", + "description": "Maximum value of the aggregated metric. Should not be set for a measurement.", + "x-nullable": true + }, + "stdDev": { + "type": "number", + "format": "double", + "description": "Standard deviation of the aggregated metric. Should not be set for a measurement.", + "x-nullable": true } } }, + "DataPointType": { + "type": "string", + "description": "Type of the metric data measurement.", + "enum": ["Measurement", "Aggregation"] + }, "Domain": { "x-ms-client-name": "MonitorDomain", "type": "object", "description": "The abstract common base of all domains.", - "discriminator": "typename", - "required": ["typename", "ver"], + "required": ["ver"], "properties": { "ver": { "x-ms-client-name": "version", @@ -118,12 +266,45 @@ "format": "int32", "description": "Schema version", "default": 2 - }, - "typename": { - "type": "string" } } }, + "EventData": { + "x-ms-client-name": "TelemetryEventData", + "allOf": [ + { + "$ref": "#/definitions/Domain" + }, + { + "type": "object", + "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.", + "required": ["name"], + "properties": { + "name": { + "type": "string", + "description": "Event name. Keep it low cardinality to allow proper grouping and useful metrics.", + "maxLength": 512 + }, + "properties": { + "type": "object", + "description": "Collection of custom properties.", + "additionalProperties": { + "type": "string", + "maxLength": 8192 + } + }, + "measurements": { + "type": "object", + "description": "Collection of custom measurements.", + "additionalProperties": { + "type": "number", + "format": "double" + } + } + } + } + ] + }, "RemoteDependencyData": { "allOf": [ { @@ -257,6 +438,43 @@ } ] }, + "SeverityLevel": { + "type": "string", + "description": "Defines the level of severity for the event.", + "enum": ["Verbose", "Information", "Warning", "Error", "Critical"] + }, + "StackFrame": { + "type": "object", + "description": "Stack frame information.", + "required": ["level", "method"], + "properties": { + "level": { + "type": "number", + "format": "int32", + "description": "" + }, + "method": { + "type": "string", + "description": "Method name.", + "maxLength": 1024 + }, + "assembly": { + "type": "string", + "description": "Name of the assembly (dll, jar, etc.) containing this function.", + "maxLength": 1024 + }, + "fileName": { + "type": "string", + "description": "File name or URL of the method implementation.", + "maxLength": 1024 + }, + "line": { + "type": "number", + "format": "int32", + "description": "Line number of the code implementation." + } + } + }, "TrackResponse": { "description": "Response containing the status of each telemetry item.", "type": "object", diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts index e8e20be8a2ee..55a443da9f79 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts @@ -18,7 +18,12 @@ export const assertData = (actual: Base, expected: Base): void => { if (expected.baseData) { assert.ok(actual.baseData); for (const [key, value] of Object.entries(expected.baseData)) { - assert.deepStrictEqual(actual.baseData![key], value, `baseData.${key} should be equal`); + const serializedKey = EnvelopeMapper.type.modelProperties![key]?.serializedName ?? key; + assert.deepStrictEqual( + actual.baseData![serializedKey], + value, + `baseData.${serializedKey} should be equal` + ); } } }; diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/common/scenario/basic.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/common/scenario/basic.ts index c72258e49ec1..7d19c6804573 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/common/scenario/basic.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/common/scenario/basic.ts @@ -43,7 +43,7 @@ export class BasicScenario implements Scenario { parent: root, kind: opentelemetry.SpanKind.CLIENT, attributes: { - numbers: 123 + numbers: "123" } }); @@ -52,7 +52,7 @@ export class BasicScenario implements Scenario { parent: root, kind: opentelemetry.SpanKind.CLIENT, attributes: { - numbers: 1234 + numbers: "1234" } }); @@ -106,7 +106,7 @@ export class BasicScenario implements Scenario { success: true, resultCode: "0", properties: { - numbers: 123 as any + numbers: "123" } } as any }, @@ -123,7 +123,7 @@ export class BasicScenario implements Scenario { success: true, resultCode: "0", properties: { - numbers: 1234 as any + numbers: "1234" } } as any }, diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/functional/trace.test.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/functional/trace.test.ts index 6843fd8a9e32..b189bb7514d1 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/functional/trace.test.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/functional/trace.test.ts @@ -18,7 +18,6 @@ describe("Trace Exporter Scenarios", () => { // todo: gzip is not supported by generated applicationInsightsClient // const buffer = gunzipSync(Buffer.from(body, "hex")); // ingest.push(...(JSON.parse(buffer.toString("utf8")) as Envelope[])); - console.log(body[0].data?.baseData); ingest.push(...body); return true; }) diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/spanUtils.test.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/spanUtils.test.ts index 15caa2574d3c..974a6a9187bf 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/spanUtils.test.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/spanUtils.test.ts @@ -305,7 +305,6 @@ describe("spanUtils.ts", () => { }; const expectedBaseData: RequestData = { - typename: "RequestData", duration: msToTimeSpan(hrTimeToMilliseconds(span.duration)), id: `|${span.spanContext.traceId}.${span.spanContext.spanId}.`, success: true, @@ -356,7 +355,6 @@ describe("spanUtils.ts", () => { }; const expectedBaseData: RemoteDependencyData = { - typename: "RemoteDependencyData", duration: msToTimeSpan(hrTimeToMilliseconds(span.duration)), id: `|traceid.spanId.`, success: true, From 5c91421feacb19ae4f5e978859e0e77c3218994e Mon Sep 17 00:00:00 2001 From: Mark Wolff Date: Thu, 24 Sep 2020 15:24:12 -0700 Subject: [PATCH 09/13] use latest codegen --- .../src/generated/models/index.ts | 265 ++++++++-- .../src/generated/models/mappers.ts | 475 ++++++++++++++---- .../src/utils/spanUtils.ts | 12 +- .../swagger/README.md | 3 +- .../test/unit/export/export.test.ts | 10 +- .../unit/platform/nodejs/httpSender.test.ts | 2 +- .../nodejs/persist/fileSystemPersist.test.ts | 2 +- .../test/unit/utils/spanUtils.test.ts | 2 +- 8 files changed, 612 insertions(+), 159 deletions(-) diff --git a/sdk/monitor/monitor-opentelemetry-exporter/src/generated/models/index.ts b/sdk/monitor/monitor-opentelemetry-exporter/src/generated/models/index.ts index 6bae7baa66c1..992703831040 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/src/generated/models/index.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/src/generated/models/index.ts @@ -8,11 +8,6 @@ import * as coreHttp from "@azure/core-http"; -export type MonitorBaseUnion = - | MonitorBase - | RequestTelemetry - | RemoteDependencyTelememetry; - /** * System variables for a telemetry item. */ @@ -28,7 +23,7 @@ export interface TelemetryItem { /** * 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. */ - time: Date; + time: string; /** * Sampling rate used in application. This telemetry item represents 1 / sampleRate actual telemetry items. */ @@ -48,7 +43,7 @@ export interface TelemetryItem { /** * Telemetry data item. */ - data?: MonitorBaseUnion; + data?: MonitorBase; } /** @@ -56,13 +51,27 @@ export interface TelemetryItem { */ export interface MonitorBase { /** - * Polymorphic discriminator, which specifies the different types this object can be + * Name of item (B section) if any. If telemetry data is derived straight from this, this should be null. + */ + baseType?: string; + /** + * The data payload for the telemetry request */ - baseType: "RequestData" | "RemoteDependencyData"; + baseData?: MonitorDomain; +} + +/** + * The abstract common base of all domains. + */ +export interface MonitorDomain { /** * Describes unknown properties. The value of an unknown property can be of "any" type. */ [property: string]: any; + /** + * Schema version + */ + version: number; } /** @@ -101,16 +110,6 @@ export interface TelemetryErrorDetails { message?: string; } -/** - * The abstract common base of all domains. - */ -export interface MonitorDomain { - /** - * Schema version - */ - version: number; -} - /** * Metric data single measurement. */ @@ -149,6 +148,40 @@ export interface MetricDataPoint { stdDev?: number; } +/** + * Exception details of the exception in a chain. + */ +export interface TelemetryExceptionDetails { + /** + * In case exception is nested (outer exception contains inner one), the id and outerId properties are used to represent the nesting. + */ + id?: number; + /** + * The value of outerId is a reference to an element in ExceptionDetails that represents the outer exception + */ + outerId?: number; + /** + * Exception type name. + */ + typeName?: string; + /** + * Exception message. + */ + message: string; + /** + * Indicates if full exception stack is provided in the exception. The stack may be trimmed, such as in the case of a StackOverflow exception. + */ + hasFullStack?: boolean; + /** + * Text describing the stack. Either stack or parsedStack should have a value. + */ + stack?: string; + /** + * List of stack frames. Either stack or parsedStack should have a value. + */ + parsedStack?: StackFrame[]; +} + /** * Stack frame information. */ @@ -172,20 +205,6 @@ export interface StackFrame { line?: number; } -export type RequestTelemetry = MonitorBase & { - /** - * An instance of PageView represents a generic action on a page like a button click. It is also the base type for PageView. - */ - baseData: RequestData; -}; - -export type RemoteDependencyTelememetry = MonitorBase & { - /** - * An instance of Remote Dependency represents an interaction of the monitored component with a remote component/service like SQL or an HTTP endpoint. - */ - baseData: RemoteDependencyData; -}; - /** * Instances of AvailabilityData represent the result of executing an availability test. */ @@ -224,38 +243,160 @@ export type AvailabilityData = MonitorDomain & { measurements?: { [propertyName: string]: number }; }; +/** + * 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. + */ +export type TelemetryEventData = MonitorDomain & { + /** + * Event name. Keep it low cardinality to allow proper grouping and useful metrics. + */ + name: string; + /** + * Collection of custom properties. + */ + properties?: { [propertyName: string]: string }; + /** + * Collection of custom measurements. + */ + measurements?: { [propertyName: string]: number }; +}; + +/** + * An instance of Exception represents a handled or unhandled exception that occurred during execution of the monitored application. + */ +export type TelemetryExceptionData = MonitorDomain & { + /** + * Exception chain - list of inner exceptions. + */ + exceptions: TelemetryExceptionDetails[]; + /** + * Severity level. Mostly used to indicate exception severity level when it is reported by logging library. + */ + severityLevel?: SeverityLevel; + /** + * 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. + */ + problemId?: string; + /** + * Collection of custom properties. + */ + properties?: { [propertyName: string]: string }; + /** + * Collection of custom measurements. + */ + measurements?: { [propertyName: string]: number }; +}; + +/** + * Instances of Message represent printf-like trace statements that are text-searched. Log4Net, NLog and other text-based log file entries are translated into instances of this type. The message does not have measurements. + */ +export type MessageData = MonitorDomain & { + /** + * Trace message + */ + message: string; + /** + * Trace severity level. + */ + severityLevel?: SeverityLevel; + /** + * Collection of custom properties. + */ + properties?: { [propertyName: string]: string }; + /** + * Collection of custom measurements. + */ + measurements?: { [propertyName: string]: number }; +}; + +/** + * An instance of the Metric item is a list of measurements (single data points) and/or aggregations. + */ +export type MetricsData = MonitorDomain & { + /** + * List of metrics. Only one metric in the list is currently supported by Application Insights storage. If multiple data points were sent only the first one will be used. + */ + metrics: MetricDataPoint[]; + /** + * Collection of custom properties. + */ + properties?: { [propertyName: string]: string }; +}; + /** * An instance of PageView represents a generic action on a page like a button click. It is also the base type for PageView. */ -export type RequestData = MonitorDomain & { +export type PageViewData = MonitorDomain & { /** - * Identifier of a request call instance. Used for correlation between request and other telemetry items. + * Identifier of a page view instance. Used for correlation between page view and other telemetry items. */ id: string; /** - * 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}'. + * Event name. Keep it low cardinality to allow proper grouping and useful metrics. */ - name?: string; + name: string; /** - * Request duration in format: DD.HH:MM:SS.MMMMMM. Must be less than 1000 days. + * Request URL with all query string parameters */ - duration: string; + url?: string; /** - * Indication of successful or unsuccessful call. + * Request duration in format: DD.HH:MM:SS.MMMMMM. For a page view (PageViewData), this is the duration. For a page view with performance information (PageViewPerfData), this is the page load time. Must be less than 1000 days. */ - success: boolean; + duration?: string; /** - * Result of a request execution. HTTP status code for HTTP requests. + * Fully qualified page URI or URL of the referring page; if unknown, leave blank */ - responseCode: string; + referredUri?: string; /** - * Source of the request. Examples are the instrumentation key of the caller or the ip address of the caller. + * Collection of custom properties. */ - source?: string; + properties?: { [propertyName: string]: string }; /** - * Request URL with all query string parameters. + * Collection of custom measurements. + */ + measurements?: { [propertyName: string]: number }; +}; + +/** + * 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. + */ +export type PageViewPerfData = MonitorDomain & { + /** + * Identifier of a page view instance. Used for correlation between page view and other telemetry items. + */ + id: string; + /** + * Event name. Keep it low cardinality to allow proper grouping and useful metrics. + */ + name: string; + /** + * Request URL with all query string parameters */ url?: string; + /** + * Request duration in format: DD.HH:MM:SS.MMMMMM. For a page view (PageViewData), this is the duration. For a page view with performance information (PageViewPerfData), this is the page load time. Must be less than 1000 days. + */ + duration?: string; + /** + * Performance total in TimeSpan 'G' (general long) format: d:hh:mm:ss.fffffff + */ + perfTotal?: string; + /** + * Network connection time in TimeSpan 'G' (general long) format: d:hh:mm:ss.fffffff + */ + networkConnect?: string; + /** + * Sent request time in TimeSpan 'G' (general long) format: d:hh:mm:ss.fffffff + */ + sentRequest?: string; + /** + * Received response time in TimeSpan 'G' (general long) format: d:hh:mm:ss.fffffff + */ + receivedResponse?: string; + /** + * DOM processing time in TimeSpan 'G' (general long) format: d:hh:mm:ss.fffffff + */ + domProcessing?: string; /** * Collection of custom properties. */ @@ -313,13 +454,37 @@ export type RemoteDependencyData = MonitorDomain & { }; /** - * 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. + * 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. */ -export type TelemetryEventData = MonitorDomain & { +export type RequestData = MonitorDomain & { /** - * Event name. Keep it low cardinality to allow proper grouping and useful metrics. + * Identifier of a request call instance. Used for correlation between request and other telemetry items. */ - name: string; + id: string; + /** + * 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}'. + */ + name?: string; + /** + * Request duration in format: DD.HH:MM:SS.MMMMMM. Must be less than 1000 days. + */ + duration: string; + /** + * Indication of successful or unsuccessful call. + */ + success: boolean; + /** + * Result of a request execution. HTTP status code for HTTP requests. + */ + responseCode: string; + /** + * Source of the request. Examples are the instrumentation key of the caller or the ip address of the caller. + */ + source?: string; + /** + * Request URL with all query string parameters. + */ + url?: string; /** * Collection of custom properties. */ diff --git a/sdk/monitor/monitor-opentelemetry-exporter/src/generated/models/mappers.ts b/sdk/monitor/monitor-opentelemetry-exporter/src/generated/models/mappers.ts index fa957b7947f7..1bdd1eded469 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/src/generated/models/mappers.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/src/generated/models/mappers.ts @@ -31,7 +31,7 @@ export const TelemetryItem: coreHttp.CompositeMapper = { serializedName: "time", required: true, type: { - name: "DateTime" + name: "String" } }, sampleRate: { @@ -75,23 +75,40 @@ export const TelemetryItem: coreHttp.CompositeMapper = { }; export const MonitorBase: coreHttp.CompositeMapper = { - serializedName: "MonitorBase", type: { name: "Composite", className: "MonitorBase", - uberParent: "MonitorBase", - additionalProperties: { type: { name: "Object" } }, - polymorphicDiscriminator: { - serializedName: "baseType", - clientName: "baseType" - }, modelProperties: { baseType: { serializedName: "baseType", - required: true, type: { name: "String" } + }, + baseData: { + serializedName: "baseData", + type: { + name: "Composite", + className: "MonitorDomain" + } + } + } + } +}; + +export const MonitorDomain: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "MonitorDomain", + additionalProperties: { type: { name: "Object" } }, + modelProperties: { + version: { + defaultValue: 2, + serializedName: "ver", + required: true, + type: { + name: "Number" + } } } } @@ -154,23 +171,6 @@ export const TelemetryErrorDetails: coreHttp.CompositeMapper = { } }; -export const MonitorDomain: coreHttp.CompositeMapper = { - type: { - name: "Composite", - className: "MonitorDomain", - modelProperties: { - version: { - defaultValue: 2, - serializedName: "ver", - required: true, - type: { - name: "Number" - } - } - } - } -}; - export const MetricDataPoint: coreHttp.CompositeMapper = { type: { name: "Composite", @@ -236,6 +236,69 @@ export const MetricDataPoint: coreHttp.CompositeMapper = { } }; +export const TelemetryExceptionDetails: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "TelemetryExceptionDetails", + modelProperties: { + id: { + serializedName: "id", + type: { + name: "Number" + } + }, + outerId: { + serializedName: "outerId", + type: { + name: "Number" + } + }, + typeName: { + constraints: { + MaxLength: 1024 + }, + serializedName: "typeName", + type: { + name: "String" + } + }, + message: { + constraints: { + MaxLength: 32768 + }, + serializedName: "message", + required: true, + type: { + name: "String" + } + }, + hasFullStack: { + defaultValue: true, + serializedName: "hasFullStack", + type: { + name: "Boolean" + } + }, + stack: { + constraints: { + MaxLength: 32768 + }, + serializedName: "stack", + type: { + name: "String" + } + }, + parsedStack: { + serializedName: "parsedStack", + type: { + name: "Sequence", + element: { type: { name: "Composite", className: "StackFrame" } } + } + } + } + } +}; + export const StackFrame: coreHttp.CompositeMapper = { type: { name: "Composite", @@ -286,52 +349,11 @@ export const StackFrame: coreHttp.CompositeMapper = { } }; -export const RequestTelemetry: coreHttp.CompositeMapper = { - serializedName: "RequestData", - type: { - name: "Composite", - className: "RequestTelemetry", - uberParent: "MonitorBase", - additionalProperties: { type: { name: "Object" } }, - polymorphicDiscriminator: MonitorBase.type.polymorphicDiscriminator, - modelProperties: { - ...MonitorBase.type.modelProperties, - baseData: { - serializedName: "baseData", - type: { - name: "Composite", - className: "RequestData" - } - } - } - } -}; - -export const RemoteDependencyTelememetry: coreHttp.CompositeMapper = { - serializedName: "RemoteDependencyData", - type: { - name: "Composite", - className: "RemoteDependencyTelememetry", - uberParent: "MonitorBase", - additionalProperties: { type: { name: "Object" } }, - polymorphicDiscriminator: MonitorBase.type.polymorphicDiscriminator, - modelProperties: { - ...MonitorBase.type.modelProperties, - baseData: { - serializedName: "baseData", - type: { - name: "Composite", - className: "RemoteDependencyData" - } - } - } - } -}; - export const AvailabilityData: coreHttp.CompositeMapper = { type: { name: "Composite", className: "AvailabilityData", + additionalProperties: { type: { name: "Object" } }, modelProperties: { ...MonitorDomain.type.modelProperties, id: { @@ -404,10 +426,163 @@ export const AvailabilityData: coreHttp.CompositeMapper = { } }; -export const RequestData: coreHttp.CompositeMapper = { +export const TelemetryEventData: coreHttp.CompositeMapper = { type: { name: "Composite", - className: "RequestData", + className: "TelemetryEventData", + additionalProperties: { type: { name: "Object" } }, + modelProperties: { + ...MonitorDomain.type.modelProperties, + name: { + constraints: { + MaxLength: 512 + }, + serializedName: "name", + required: true, + type: { + name: "String" + } + }, + properties: { + serializedName: "properties", + type: { + name: "Dictionary", + value: { type: { name: "String" }, constraints: { MaxLength: 8192 } } + } + }, + measurements: { + serializedName: "measurements", + type: { + name: "Dictionary", + value: { type: { name: "Number" } } + } + } + } + } +}; + +export const TelemetryExceptionData: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "TelemetryExceptionData", + additionalProperties: { type: { name: "Object" } }, + modelProperties: { + ...MonitorDomain.type.modelProperties, + exceptions: { + serializedName: "exceptions", + required: true, + type: { + name: "Sequence", + element: { + type: { name: "Composite", className: "TelemetryExceptionDetails" } + } + } + }, + severityLevel: { + serializedName: "severityLevel", + type: { + name: "String" + } + }, + problemId: { + constraints: { + MaxLength: 1024 + }, + serializedName: "problemId", + type: { + name: "String" + } + }, + properties: { + serializedName: "properties", + type: { + name: "Dictionary", + value: { type: { name: "String" }, constraints: { MaxLength: 8192 } } + } + }, + measurements: { + serializedName: "measurements", + type: { + name: "Dictionary", + value: { type: { name: "Number" } } + } + } + } + } +}; + +export const MessageData: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "MessageData", + additionalProperties: { type: { name: "Object" } }, + modelProperties: { + ...MonitorDomain.type.modelProperties, + message: { + constraints: { + MaxLength: 32768 + }, + serializedName: "message", + required: true, + type: { + name: "String" + } + }, + severityLevel: { + serializedName: "severityLevel", + type: { + name: "String" + } + }, + properties: { + serializedName: "properties", + type: { + name: "Dictionary", + value: { type: { name: "String" }, constraints: { MaxLength: 8192 } } + } + }, + measurements: { + serializedName: "measurements", + type: { + name: "Dictionary", + value: { type: { name: "Number" } } + } + } + } + } +}; + +export const MetricsData: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "MetricsData", + additionalProperties: { type: { name: "Object" } }, + modelProperties: { + ...MonitorDomain.type.modelProperties, + metrics: { + serializedName: "metrics", + required: true, + type: { + name: "Sequence", + element: { type: { name: "Composite", className: "MetricDataPoint" } } + } + }, + properties: { + serializedName: "properties", + type: { + name: "Dictionary", + value: { type: { name: "String" }, constraints: { MaxLength: 8192 } } + } + } + } + } +}; + +export const PageViewData: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "PageViewData", + additionalProperties: { type: { name: "Object" } }, modelProperties: { ...MonitorDomain.type.modelProperties, id: { @@ -425,40 +600,76 @@ export const RequestData: coreHttp.CompositeMapper = { MaxLength: 1024 }, serializedName: "name", + required: true, + type: { + name: "String" + } + }, + url: { + constraints: { + MaxLength: 2048 + }, + serializedName: "url", type: { name: "String" } }, duration: { serializedName: "duration", - required: true, type: { name: "String" } }, - success: { - defaultValue: true, - serializedName: "success", - required: true, + referredUri: { + constraints: { + MaxLength: 2048 + }, + serializedName: "referredUri", type: { - name: "Boolean" + name: "String" } }, - responseCode: { + properties: { + serializedName: "properties", + type: { + name: "Dictionary", + value: { type: { name: "String" }, constraints: { MaxLength: 8192 } } + } + }, + measurements: { + serializedName: "measurements", + type: { + name: "Dictionary", + value: { type: { name: "Number" } } + } + } + } + } +}; + +export const PageViewPerfData: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "PageViewPerfData", + additionalProperties: { type: { name: "Object" } }, + modelProperties: { + ...MonitorDomain.type.modelProperties, + id: { constraints: { - MaxLength: 1024 + MaxLength: 512 }, - serializedName: "responseCode", + serializedName: "id", required: true, type: { name: "String" } }, - source: { + name: { constraints: { MaxLength: 1024 }, - serializedName: "source", + serializedName: "name", + required: true, type: { name: "String" } @@ -472,6 +683,42 @@ export const RequestData: coreHttp.CompositeMapper = { name: "String" } }, + duration: { + serializedName: "duration", + type: { + name: "String" + } + }, + perfTotal: { + serializedName: "perfTotal", + type: { + name: "String" + } + }, + networkConnect: { + serializedName: "networkConnect", + type: { + name: "String" + } + }, + sentRequest: { + serializedName: "sentRequest", + type: { + name: "String" + } + }, + receivedResponse: { + serializedName: "receivedResponse", + type: { + name: "String" + } + }, + domProcessing: { + serializedName: "domProcessing", + type: { + name: "String" + } + }, properties: { serializedName: "properties", type: { @@ -494,6 +741,7 @@ export const RemoteDependencyData: coreHttp.CompositeMapper = { type: { name: "Composite", className: "RemoteDependencyData", + additionalProperties: { type: { name: "Object" } }, modelProperties: { ...MonitorDomain.type.modelProperties, id: { @@ -583,22 +831,75 @@ export const RemoteDependencyData: coreHttp.CompositeMapper = { } }; -export const TelemetryEventData: coreHttp.CompositeMapper = { +export const RequestData: coreHttp.CompositeMapper = { type: { name: "Composite", - className: "TelemetryEventData", + className: "RequestData", + additionalProperties: { type: { name: "Object" } }, modelProperties: { ...MonitorDomain.type.modelProperties, - name: { + id: { constraints: { MaxLength: 512 }, + serializedName: "id", + required: true, + type: { + name: "String" + } + }, + name: { + constraints: { + MaxLength: 1024 + }, serializedName: "name", + type: { + name: "String" + } + }, + duration: { + serializedName: "duration", required: true, type: { name: "String" } }, + success: { + defaultValue: true, + serializedName: "success", + required: true, + type: { + name: "Boolean" + } + }, + responseCode: { + constraints: { + MaxLength: 1024 + }, + serializedName: "responseCode", + required: true, + type: { + name: "String" + } + }, + source: { + constraints: { + MaxLength: 1024 + }, + serializedName: "source", + type: { + name: "String" + } + }, + url: { + constraints: { + MaxLength: 2048 + }, + serializedName: "url", + type: { + name: "String" + } + }, properties: { serializedName: "properties", type: { @@ -616,9 +917,3 @@ export const TelemetryEventData: coreHttp.CompositeMapper = { } } }; - -export let discriminators = { - MonitorBase: MonitorBase, - "MonitorBase.RequestData": RequestTelemetry, - "MonitorBase.RemoteDependencyData": RemoteDependencyTelememetry -}; diff --git a/sdk/monitor/monitor-opentelemetry-exporter/src/utils/spanUtils.ts b/sdk/monitor/monitor-opentelemetry-exporter/src/utils/spanUtils.ts index 311f6af57105..58228824f1b3 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/src/utils/spanUtils.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/src/utils/spanUtils.ts @@ -30,13 +30,7 @@ import { getInstance } from "../platform"; import { DB_STATEMENT, DB_TYPE, DB_INSTANCE } from "./constants/span/dbAttributes"; import { parseEventHubSpan } from "./eventhub"; import { AzNamespace, MicrosoftEventHub } from "./constants/span/azAttributes"; -import { - RemoteDependencyData, - RemoteDependencyTelememetry, - RequestData, - RequestTelemetry, - TelemetryItem as Envelope -} from "../generated"; +import { RemoteDependencyData, RequestData, TelemetryItem as Envelope } from "../generated"; function createTagsFromSpan(span: ReadableSpan): Tags { const context = getInstance(); @@ -200,7 +194,7 @@ export function readableSpanToEnvelope( ): Envelope { const envelope: Partial = {}; envelope.sampleRate = 100; - envelope.data = {} as RemoteDependencyTelememetry | RequestTelemetry; + envelope.data = {}; const tags = createTagsFromSpan(span); const [properties, measurements] = createPropertiesFromSpan(span); let data; @@ -236,7 +230,7 @@ export function readableSpanToEnvelope( measurements } as RequestData | RemoteDependencyData; envelope.tags = tags; - envelope.time = new Date(hrTimeToMilliseconds(span.startTime)); + envelope.time = new Date(hrTimeToMilliseconds(span.startTime)).toISOString(); envelope.instrumentationKey = instrumentationKey; envelope.version = 1; diff --git a/sdk/monitor/monitor-opentelemetry-exporter/swagger/README.md b/sdk/monitor/monitor-opentelemetry-exporter/swagger/README.md index 8d34ecae7525..63f4fe4727ef 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/swagger/README.md +++ b/sdk/monitor/monitor-opentelemetry-exporter/swagger/README.md @@ -21,8 +21,7 @@ generate-metadata: false license-header: MICROSOFT_MIT_NO_VERSION output-folder: ../ source-code-folder-path: ./src/generated -input-file: ./swagger.json -# input-file: https://github.com/srnagar/swagger/blob/master/application-insights.json +input-file: https://github.com/srnagar/azure-rest-api-specs/blob/master/specification/applicationinsights/data-plane/Monitor.Exporters/preview/2020-09-15_Preview/swagger.json add-credentials: false use-extension: "@autorest/typescript": "6.0.0-dev.20200826.1" diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/export/export.test.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/export/export.test.ts index f17f638fea11..47e7644170a4 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/export/export.test.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/export/export.test.ts @@ -50,7 +50,7 @@ describe("#AzureMonitorBaseExporter", () => { const scope = nock(DEFAULT_BREEZE_ENDPOINT).post("/v2/track"); const envelope = { name: "Name", - time: new Date() + time: new Date().toISOString() }; before(() => { @@ -167,11 +167,11 @@ describe("#AzureMonitorBaseExporter", () => { it("should filter envelopes", () => { const fooEnvelope = { name: "foo", - time: new Date() + time: new Date().toISOString() }; const barEnvelope = { name: "bar", - time: new Date() + time: new Date().toISOString() }; const exporter = new TestExporter(); @@ -188,11 +188,11 @@ describe("#AzureMonitorBaseExporter", () => { it("should filter modified envelopes", () => { const fooEnvelope = { name: "foo", - time: new Date() + time: new Date().toISOString() }; const barEnvelope = { name: "bar", - time: new Date() + time: new Date().toISOString() }; const exporter = new TestExporter(); diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/platform/nodejs/httpSender.test.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/platform/nodejs/httpSender.test.ts index 2bdc5772aa97..ff17e178ce55 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/platform/nodejs/httpSender.test.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/platform/nodejs/httpSender.test.ts @@ -31,7 +31,7 @@ describe("HttpSender", () => { describe("#send()", () => { const envelope: Envelope = { name: "name", - time: new Date() + time: new Date().toISOString() }; it("should send a valid envelope", async () => { const sender = new HttpSender(); diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/platform/nodejs/persist/fileSystemPersist.test.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/platform/nodejs/persist/fileSystemPersist.test.ts index db87bb771c4e..8cbd5783c869 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/platform/nodejs/persist/fileSystemPersist.test.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/platform/nodejs/persist/fileSystemPersist.test.ts @@ -75,7 +75,7 @@ describe("FileSystemPersist", () => { it("should store to disk the value provided", async () => { const envelope: Envelope = { name: "name", - time: new Date() + time: new Date().toISOString() }; const persister = new FileSystemPersist({ instrumentationKey }); const envelopes = [envelope]; diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/spanUtils.test.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/spanUtils.test.ts index 974a6a9187bf..7241d1be2c69 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/spanUtils.test.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/spanUtils.test.ts @@ -46,7 +46,7 @@ function assertEnvelope( assert.ok(envelope.data); if (expectedTime) { - assert.strictEqual(envelope.time.toISOString(), expectedTime.toISOString()); + assert.strictEqual(envelope.time, expectedTime.toISOString()); } assert.deepStrictEqual(envelope.tags, { ...context.tags, ...expectedTags }); From 8d9f34d95d0bf6efd7efacb6109c1160abf1231a Mon Sep 17 00:00:00 2001 From: Mark Wolff Date: Mon, 5 Oct 2020 13:11:40 -0700 Subject: [PATCH 10/13] use latest swagger --- .../swagger/README.md | 2 +- .../swagger/swagger.json | 711 ------------------ 2 files changed, 1 insertion(+), 712 deletions(-) delete mode 100644 sdk/monitor/monitor-opentelemetry-exporter/swagger/swagger.json diff --git a/sdk/monitor/monitor-opentelemetry-exporter/swagger/README.md b/sdk/monitor/monitor-opentelemetry-exporter/swagger/README.md index 63f4fe4727ef..f70fd71200b2 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/swagger/README.md +++ b/sdk/monitor/monitor-opentelemetry-exporter/swagger/README.md @@ -21,7 +21,7 @@ generate-metadata: false license-header: MICROSOFT_MIT_NO_VERSION output-folder: ../ source-code-folder-path: ./src/generated -input-file: https://github.com/srnagar/azure-rest-api-specs/blob/master/specification/applicationinsights/data-plane/Monitor.Exporters/preview/2020-09-15_Preview/swagger.json +input-file: https://github.com/azure/azure-rest-api-specs/blob/master/specification/applicationinsights/data-plane/Monitor.Exporters/preview/2020-09-15_Preview/swagger.json add-credentials: false use-extension: "@autorest/typescript": "6.0.0-dev.20200826.1" diff --git a/sdk/monitor/monitor-opentelemetry-exporter/swagger/swagger.json b/sdk/monitor/monitor-opentelemetry-exporter/swagger/swagger.json deleted file mode 100644 index b9ad49a30ad9..000000000000 --- a/sdk/monitor/monitor-opentelemetry-exporter/swagger/swagger.json +++ /dev/null @@ -1,711 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "version": "2020-09-15_Preview", - "title": "ApplicationInsightsClient", - "description": "This document describes the protocol for client requests and responses to the data collection endpoint." - }, - "x-ms-parameterized-host": { - "hostTemplate": "{Host}/v2/", - "useSchemePrefix": false, - "parameters": [ - { - "$ref": "#/parameters/Host" - } - ] - }, - "paths": { - "/track": { - "post": { - "summary": "Track telemetry events", - "description": "This operation sends a sequence of telemetry events that will be monitored by Azure Monitor.", - "operationId": "track", - "parameters": [ - { - "name": "body", - "in": "body", - "description": "The list of telemetry events to track.", - "required": true, - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/TelemetryEnvelope" - } - } - } - ], - "consumes": ["application/json", "x-json-stream"], - "produces": ["application/json"], - "responses": { - "200": { - "description": "All of the telemetry items were accepted and processed.", - "schema": { - "$ref": "#/definitions/TrackResponse" - } - }, - "206": { - "description": "Partial success. Some of the telemetry items were accepted and processed.", - "schema": { - "$ref": "#/definitions/TrackResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/TrackResponse" - } - }, - "402": { - "description": "Payment Required", - "schema": { - "$ref": "#/definitions/TrackResponse" - } - }, - "429": { - "description": "Too Many Requests", - "schema": { - "$ref": "#/definitions/TrackResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/TrackResponse" - } - }, - "503": { - "description": "Service Unavailable", - "schema": { - "$ref": "#/definitions/TrackResponse" - } - } - }, - "x-ms-examples": { - "Track examples": { - "$ref": ".//examples//track.json" - } - } - } - } - }, - "definitions": { - "AvailabilityData": { - "allOf": [ - { - "$ref": "#/definitions/Domain" - }, - { - "type": "object", - "description": "Instances of AvailabilityData represent the result of executing an availability test.", - "required": ["id", "name", "duration", "success"], - "properties": { - "id": { - "type": "string", - "description": "Identifier of a test run. Use it to correlate steps of test run and telemetry generated by the service.", - "maxLength": 512 - }, - "name": { - "type": "string", - "description": "Name of the test that these availability results represent.", - "maxLength": 1024 - }, - "duration": { - "type": "string", - "description": "Duration in format: DD.HH:MM:SS.MMMMMM. Must be less than 1000 days." - }, - "success": { - "type": "boolean", - "x-nullable": false, - "description": "Success flag." - }, - "runLocation": { - "type": "string", - "description": "Name of the location where the test was run from.", - "maxLength": 1024 - }, - "message": { - "type": "string", - "description": "Diagnostic message for the result.", - "maxLength": 8192 - }, - "properties": { - "type": "object", - "description": "Collection of custom properties.", - "additionalProperties": { - "type": "string", - "maxLength": 8192 - } - }, - "measurements": { - "type": "object", - "description": "Collection of custom measurements.", - "additionalProperties": { - "type": "number", - "format": "double" - } - } - } - } - ] - }, - "Base": { - "x-ms-client-name": "MonitorBase", - "type": "object", - "description": "Data struct to contain only C section with custom fields.", - "discriminator": "baseType", - "required": ["baseType", "baseData"], - "additionalProperties": true, - "properties": { - "baseType": { - "type": "string", - "description": "Name of item (B section) if any. If telemetry data is derived straight from this, this should be null." - } - } - }, - "RequestTelemetry": { - "x-ms-discriminator-value": "RequestData", - "required": ["baseType", "baseData"], - "allOf": [ - { - "$ref": "#/definitions/Base" - }, - { - "type": "object", - "properties": { - "baseData": { - "$ref": "#/definitions/RequestData" - } - } - } - ] - }, - "RemoteDependencyTelememetry": { - "x-ms-discriminator-value": "RemoteDependencyData", - "required": ["baseType", "baseData"], - "allOf": [ - { - "$ref": "#/definitions/Base" - }, - { - "type": "object", - "properties": { - "baseData": { - "$ref": "#/definitions/RemoteDependencyData" - } - } - } - ] - }, - "DataPoint": { - "x-ms-client-name": "MetricDataPoint", - "type": "object", - "description": "Metric data single measurement.", - "required": ["name", "value"], - "properties": { - "ns": { - "x-ms-client-name": "namespace", - "type": "string", - "description": "Namespace of the metric.", - "maxLength": 256 - }, - "name": { - "type": "string", - "description": "Name of the metric.", - "maxLength": 1024 - }, - "kind": { - "x-ms-client-name": "dataPointType", - "$ref": "#/definitions/DataPointType", - "description": "Metric type. Single measurement or the aggregated value." - }, - "value": { - "type": "number", - "description": "Single value for measurement. Sum of individual measurements for the aggregation.", - "format": "double" - }, - "count": { - "type": "number", - "format": "int32", - "description": "Metric weight of the aggregated metric. Should not be set for a measurement.", - "x-nullable": true - }, - "min": { - "type": "number", - "format": "double", - "description": "Minimum value of the aggregated metric. Should not be set for a measurement.", - "x-nullable": true - }, - "max": { - "type": "number", - "format": "double", - "description": "Maximum value of the aggregated metric. Should not be set for a measurement.", - "x-nullable": true - }, - "stdDev": { - "type": "number", - "format": "double", - "description": "Standard deviation of the aggregated metric. Should not be set for a measurement.", - "x-nullable": true - } - } - }, - "DataPointType": { - "type": "string", - "description": "Type of the metric data measurement.", - "enum": ["Measurement", "Aggregation"] - }, - "Domain": { - "x-ms-client-name": "MonitorDomain", - "type": "object", - "description": "The abstract common base of all domains.", - "required": ["ver"], - "properties": { - "ver": { - "x-ms-client-name": "version", - "type": "integer", - "format": "int32", - "description": "Schema version", - "default": 2 - } - } - }, - "EventData": { - "x-ms-client-name": "TelemetryEventData", - "allOf": [ - { - "$ref": "#/definitions/Domain" - }, - { - "type": "object", - "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.", - "required": ["name"], - "properties": { - "name": { - "type": "string", - "description": "Event name. Keep it low cardinality to allow proper grouping and useful metrics.", - "maxLength": 512 - }, - "properties": { - "type": "object", - "description": "Collection of custom properties.", - "additionalProperties": { - "type": "string", - "maxLength": 8192 - } - }, - "measurements": { - "type": "object", - "description": "Collection of custom measurements.", - "additionalProperties": { - "type": "number", - "format": "double" - } - } - } - } - ] - }, - "RemoteDependencyData": { - "allOf": [ - { - "$ref": "#/definitions/Domain" - }, - { - "type": "object", - "description": "An instance of Remote Dependency represents an interaction of the monitored component with a remote component/service like SQL or an HTTP endpoint.", - "required": ["name", "duration"], - "properties": { - "id": { - "type": "string", - "description": "Identifier of a dependency call instance. Used for correlation with the request telemetry item corresponding to this dependency call.", - "maxLength": 512 - }, - "name": { - "type": "string", - "description": "Name of the command initiated with this dependency call. Low cardinality value. Examples are stored procedure name and URL path template.", - "maxLength": 1024 - }, - "resultCode": { - "type": "string", - "description": "Result code of a dependency call. Examples are SQL error code and HTTP status code.", - "maxLength": 1024 - }, - "data": { - "type": "string", - "description": "Command initiated by this dependency call. Examples are SQL statement and HTTP URL with all query parameters.", - "maxLength": 8192 - }, - "type": { - "type": "string", - "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.", - "maxLength": 1024 - }, - "target": { - "type": "string", - "description": "Target site of a dependency call. Examples are server name, host address.", - "maxLength": 1024 - }, - "duration": { - "type": "string", - "description": "Request duration in format: DD.HH:MM:SS.MMMMMM. Must be less than 1000 days." - }, - "success": { - "type": "boolean", - "description": "Indication of successful or unsuccessful call.", - "default": true - }, - "properties": { - "type": "object", - "description": "Collection of custom properties.", - "additionalProperties": { - "type": "string", - "maxLength": 8192 - } - }, - "measurements": { - "type": "object", - "description": "Collection of custom measurements.", - "additionalProperties": { - "type": "number", - "format": "double" - } - } - } - } - ] - }, - "RequestData": { - "allOf": [ - { - "$ref": "#/definitions/Domain" - }, - { - "type": "object", - "description": "An instance of PageView represents a generic action on a page like a button click. It is also the base type for PageView.", - "required": ["id", "duration", "responseCode", "success"], - "properties": { - "id": { - "type": "string", - "description": "Identifier of a request call instance. Used for correlation between request and other telemetry items.", - "maxLength": 512 - }, - "name": { - "type": "string", - "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}'.", - "maxLength": 1024 - }, - "duration": { - "type": "string", - "description": "Request duration in format: DD.HH:MM:SS.MMMMMM. Must be less than 1000 days." - }, - "success": { - "type": "boolean", - "description": "Indication of successful or unsuccessful call.", - "default": true - }, - "responseCode": { - "type": "string", - "description": "Result of a request execution. HTTP status code for HTTP requests.", - "maxLength": 1024 - }, - "source": { - "type": "string", - "description": "Source of the request. Examples are the instrumentation key of the caller or the ip address of the caller.", - "maxLength": 1024 - }, - "url": { - "type": "string", - "description": "Request URL with all query string parameters.", - "maxLength": 2048 - }, - "properties": { - "type": "object", - "description": "Collection of custom properties.", - "additionalProperties": { - "type": "string", - "maxLength": 8192 - } - }, - "measurements": { - "type": "object", - "description": "Collection of custom measurements.", - "additionalProperties": { - "type": "number", - "format": "double" - } - } - } - } - ] - }, - "SeverityLevel": { - "type": "string", - "description": "Defines the level of severity for the event.", - "enum": ["Verbose", "Information", "Warning", "Error", "Critical"] - }, - "StackFrame": { - "type": "object", - "description": "Stack frame information.", - "required": ["level", "method"], - "properties": { - "level": { - "type": "number", - "format": "int32", - "description": "" - }, - "method": { - "type": "string", - "description": "Method name.", - "maxLength": 1024 - }, - "assembly": { - "type": "string", - "description": "Name of the assembly (dll, jar, etc.) containing this function.", - "maxLength": 1024 - }, - "fileName": { - "type": "string", - "description": "File name or URL of the method implementation.", - "maxLength": 1024 - }, - "line": { - "type": "number", - "format": "int32", - "description": "Line number of the code implementation." - } - } - }, - "TrackResponse": { - "description": "Response containing the status of each telemetry item.", - "type": "object", - "properties": { - "itemsReceived": { - "type": "number", - "format": "int32", - "description": "The number of items received." - }, - "itemsAccepted": { - "type": "number", - "format": "int32", - "description": "The number of items accepted." - }, - "errors": { - "type": "array", - "description": "An array of error detail objects.", - "items": { - "$ref": "#/definitions/ErrorDetails" - } - } - } - }, - "ErrorDetails": { - "x-ms-client-name": "TelemetryErrorDetails", - "description": "The error details", - "type": "object", - "properties": { - "index": { - "type": "number", - "format": "int32", - "description": "The index in the original payload of the item." - }, - "statusCode": { - "type": "number", - "format": "int32", - "description": "The item specific [HTTP Response status code](#Response Status Codes)." - }, - "message": { - "type": "string", - "description": "The error message." - } - } - }, - "TelemetryEnvelope": { - "x-ms-client-name": "TelemetryItem", - "description": "System variables for a telemetry item.", - "type": "object", - "required": ["name", "time"], - "properties": { - "ver": { - "type": "number", - "x-ms-client-name": "version", - "format": "int32", - "default": 1, - "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": { - "type": "string", - "description": "Type name of telemetry data item." - }, - "time": { - "type": "string", - "format": "date-time", - "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." - }, - "sampleRate": { - "type": "number", - "format": "float", - "default": 100.0, - "description": "Sampling rate used in application. This telemetry item represents 1 / sampleRate actual telemetry items." - }, - "seq": { - "type": "string", - "x-ms-client-name": "sequence", - "maxLength": 64, - "description": "Sequence field used to track absolute order of uploaded events." - }, - "iKey": { - "type": "string", - "x-ms-client-name": "instrumentationKey", - "description": "The instrumentation key of the Application Insights resource." - }, - "tags": { - "type": "object", - "description": "Key/value collection of context properties. See ContextTagKeys for information on available properties.", - "additionalProperties": { - "type": "string" - } - }, - "data": { - "$ref": "#/definitions/Base", - "description": "Telemetry data item." - } - } - }, - "ContextTagKeys": { - "type": "string", - "description": "The context tag keys.", - "enum": [ - "ApplicationVersion", - "DeviceId", - "DeviceLocale", - "DeviceModel", - "DeviceOEMName", - "DeviceOSVersion", - "DeviceType", - "LocationIp", - "LocationCountry", - "LocationProvince", - "LocationCity", - "OperationId", - "OperationName", - "OperationParentId", - "OperationSyntheticSource", - "OperationCorrelationVector", - "SessionId", - "SessionIsFirst", - "UserAccountId", - "UserId", - "UserAuthUserId", - "CloudRole", - "CloudRoleVer", - "CloudRoleInstance", - "CloudLocation", - "InternalSdkVersion", - "InternalAgentVersion", - "InternalNodeName " - ], - "x-ms-enum": { - "name": "ContextTagKeys", - "modelAsString": true, - "values": [ - { - "value": "ai.application.ver" - }, - { - "value": "ai.device.id" - }, - { - "value": "ai.device.locale" - }, - { - "value": "ai.device.model" - }, - { - "value": "ai.device.oemName" - }, - { - "value": "ai.device.osVersion" - }, - { - "value": "ai.device.type" - }, - { - "value": "ai.location.ip" - }, - { - "value": "ai.location.country" - }, - { - "value": "ai.location.province" - }, - { - "value": "ai.location.city" - }, - { - "value": "ai.operation.id" - }, - { - "value": "ai.operation.name" - }, - { - "value": "ai.operation.parentId" - }, - { - "value": "ai.operation.syntheticSource" - }, - { - "value": "ai.operation.correlationVector" - }, - { - "value": "ai.session.id" - }, - { - "value": "ai.session.isFirst" - }, - { - "value": "ai.user.accountId" - }, - { - "value": "ai.user.id" - }, - { - "value": "ai.user.authUserId" - }, - { - "value": "ai.cloud.role" - }, - { - "value": "ai.cloud.roleVer" - }, - { - "value": "ai.cloud.roleInstance" - }, - { - "value": "ai.cloud.location" - }, - { - "value": "ai.internal.sdkVersion" - }, - { - "value": "ai.internal.agentVersion" - }, - { - "value": "ai.internal.nodeName" - } - ] - } - } - }, - "parameters": { - "Host": { - "name": "Host", - "description": "Breeze endpoint: https://dc.services.visualstudio.com", - "x-ms-parameter-location": "client", - "default": "https://dc.services.visualstudio.com", - "required": true, - "type": "string", - "in": "path", - "x-ms-skip-url-encoding": true - } - } -} From 18d5098bca7ba0cac2db287bf00f65a4ed34183a Mon Sep 17 00:00:00 2001 From: Mark Wolff Date: Thu, 8 Oct 2020 11:13:39 -0700 Subject: [PATCH 11/13] fix unreachable code --- sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts index cb38e99c9d3c..10b7a2d012cd 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/common/assert.ts @@ -87,7 +87,6 @@ export const assertExpectation = (actual: Envelope[], expectations: Expectation[ (expectation.data?.baseData as RequestData).name }` ); - return; } for (const [key, value] of Object.entries(expectation) as [keyof Expectation, unknown][]) { From 424b62b3c70d8150af74d688cc62e977989a8b43 Mon Sep 17 00:00:00 2001 From: Mark Wolff Date: Thu, 8 Oct 2020 13:15:27 -0700 Subject: [PATCH 12/13] Update sdk/monitor/monitor-opentelemetry-exporter/src/platform/nodejs/httpSender.ts Co-authored-by: Jeff Fisher --- .../src/platform/nodejs/httpSender.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sdk/monitor/monitor-opentelemetry-exporter/src/platform/nodejs/httpSender.ts b/sdk/monitor/monitor-opentelemetry-exporter/src/platform/nodejs/httpSender.ts index 802519f8a4c9..ba009f4b96b9 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/src/platform/nodejs/httpSender.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/src/platform/nodejs/httpSender.ts @@ -27,9 +27,8 @@ export class HttpSender implements Sender { } async send(envelopes: Envelope[]): Promise { - const res = await this._appInsightsClient.track(envelopes); - // eslint-disable-next-line no-underscore-dangle - return { statusCode: res._response.status, result: res._response.bodyAsText || "" }; + const { _response: res } = await this._appInsightsClient.track(envelopes); + return { statusCode: res.status, result: res.bodyAsText || "" }; } shutdown(): void { From f8844d6b26716bb61461fd0fc885aa586c2df14d Mon Sep 17 00:00:00 2001 From: Mark Wolff Date: Thu, 8 Oct 2020 13:47:51 -0700 Subject: [PATCH 13/13] refactor spanUtils envelope creation --- .../src/utils/eventhub.ts | 11 ++-- .../src/utils/spanUtils.ts | 63 ++++++++++--------- .../test/unit/utils/eventhub.test.ts | 22 ++----- 3 files changed, 45 insertions(+), 51 deletions(-) diff --git a/sdk/monitor/monitor-opentelemetry-exporter/src/utils/eventhub.ts b/sdk/monitor/monitor-opentelemetry-exporter/src/utils/eventhub.ts index 23752d134671..af8eacab0bd5 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/src/utils/eventhub.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/src/utils/eventhub.ts @@ -5,7 +5,7 @@ import { SpanKind } from "@opentelemetry/api"; import { hrTimeToMilliseconds } from "@opentelemetry/core"; import { GeneralAttribute } from "@opentelemetry/semantic-conventions"; import { ReadableSpan } from "@opentelemetry/tracing"; -import { RemoteDependencyData, TelemetryItem as Envelope } from "../generated"; +import { RemoteDependencyData, RequestData } from "../generated"; import { TIME_SINCE_ENQUEUED, ENQUEUED_TIME } from "./constants/applicationinsights"; import { AzNamespace, @@ -37,17 +37,16 @@ const getTimeSinceEnqueued = (span: ReadableSpan) => { * * https://gist.github.com/lmolkova/e4215c0f44a49ef824983382762e6b92#mapping-to-azure-monitor-application-insights-telemetry */ -export const parseEventHubSpan = (span: ReadableSpan, envelope: Envelope): void => { - if (!envelope.data?.baseData) return; - +export const parseEventHubSpan = ( + span: ReadableSpan, + baseData: RequestData | RemoteDependencyData +): void => { const namespace = span.attributes[AzNamespace] as typeof MicrosoftEventHub; const peerAddress = ((span.attributes[GeneralAttribute.NET_PEER_ADDRESS] || span.attributes["peer.address"] || "unknown") as string).replace(/\/$/g, ""); // remove trailing "/" const messageBusDestination = (span.attributes[MessageBusDestination] || "unknown") as string; - const baseData = envelope.data.baseData as RemoteDependencyData; - switch (span.kind) { case SpanKind.CLIENT: baseData.type = namespace; diff --git a/sdk/monitor/monitor-opentelemetry-exporter/src/utils/spanUtils.ts b/sdk/monitor/monitor-opentelemetry-exporter/src/utils/spanUtils.ts index 58228824f1b3..f65b0e370685 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/src/utils/spanUtils.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/src/utils/spanUtils.ts @@ -189,32 +189,35 @@ function createInProcData(span: ReadableSpan): RemoteDependencyData { export function readableSpanToEnvelope( span: ReadableSpan, - instrumentationKey: string, + ikey: string, logger?: Logger ): Envelope { - const envelope: Partial = {}; - envelope.sampleRate = 100; - envelope.data = {}; + let name: string; + let baseType: "RemoteDependencyData" | "RequestData"; + const sampleRate = 100; + let baseData: RemoteDependencyData | RequestData; + + const time = new Date(hrTimeToMilliseconds(span.startTime)).toISOString(); + const instrumentationKey = ikey; const tags = createTagsFromSpan(span); const [properties, measurements] = createPropertiesFromSpan(span); - let data; switch (span.kind) { case SpanKind.CLIENT: case SpanKind.PRODUCER: - envelope.name = "Microsoft.ApplicationInsights.RemoteDependency"; - envelope.data.baseType = "RemoteDependencyData"; - data = createDependencyData(span); + name = "Microsoft.ApplicationInsights.RemoteDependency"; + baseType = "RemoteDependencyData"; + baseData = createDependencyData(span); break; case SpanKind.SERVER: case SpanKind.CONSUMER: - envelope.name = "Microsoft.ApplicationInsights.Request"; - envelope.data.baseType = "RequestData"; - data = createRequestData(span); + name = "Microsoft.ApplicationInsights.Request"; + baseType = "RequestData"; + baseData = createRequestData(span); break; case SpanKind.INTERNAL: - envelope.data.baseType = "RemoteDependencyData"; - envelope.name = "Microsoft.ApplicationInsights.RemoteDependency"; - data = createInProcData(span); + baseType = "RemoteDependencyData"; + name = "Microsoft.ApplicationInsights.RemoteDependency"; + baseData = createInProcData(span); break; default: // never @@ -224,27 +227,31 @@ export function readableSpanToEnvelope( throw new Error(`Unsupported span kind ${span.kind}`); } - envelope.data.baseData = { - ...data, - properties, - measurements - } as RequestData | RemoteDependencyData; - envelope.tags = tags; - envelope.time = new Date(hrTimeToMilliseconds(span.startTime)).toISOString(); - envelope.instrumentationKey = instrumentationKey; - envelope.version = 1; - if (span.attributes[AzNamespace] === MicrosoftEventHub) { - parseEventHubSpan(span, envelope as Envelope); + parseEventHubSpan(span, baseData); } else if (span.attributes[AzNamespace]) { switch (span.kind) { case SpanKind.INTERNAL: - (envelope.data - .baseData as RemoteDependencyData).type = `${INPROC} | ${span.attributes[AzNamespace]}`; + (baseData as RemoteDependencyData).type = `${INPROC} | ${span.attributes[AzNamespace]}`; break; default: // no op } } - return envelope as Envelope; + return { + name, + sampleRate, + time, + instrumentationKey, + tags, + version: 1, + data: { + baseType, + baseData: { + ...baseData, + properties, + measurements + } + } + }; } diff --git a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/eventhub.test.ts b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/eventhub.test.ts index 0f60e0c257ac..d3a8fb4cc213 100644 --- a/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/eventhub.test.ts +++ b/sdk/monitor/monitor-opentelemetry-exporter/test/unit/utils/eventhub.test.ts @@ -30,18 +30,6 @@ describe("#parseEventHubSpan(...)", () => { [MessageBusDestination]: destination }; - it("should not crash when provided an incomplete envelope", () => { - const span = new Span( - tracer, - "parent span", - { traceId: "traceid", spanId: "spanId", traceFlags: 0 }, - SpanKind.CLIENT, - "parentSpanId" - ); - - assert.doesNotThrow(() => parseEventHubSpan(span, ({ data: null } as unknown) as Envelope)); - }); - it("should correctly parse SpanKind.CLIENT", () => { const envelope = { data: { baseData: {} } } as Envelope; const span = new Span( @@ -52,9 +40,9 @@ describe("#parseEventHubSpan(...)", () => { ); span.setAttributes(attributes); - parseEventHubSpan(span, envelope); - const baseData = envelope.data?.baseData as RemoteDependencyData; + parseEventHubSpan(span, baseData); + assert.strictEqual(baseData.type, attributes[AzNamespace]); assert.strictEqual(baseData.target, `${peerAddress}/${destination}`); @@ -72,9 +60,9 @@ describe("#parseEventHubSpan(...)", () => { ); span.setAttributes(attributes); - parseEventHubSpan(span, envelope); - const baseData = envelope.data?.baseData as RemoteDependencyData; + parseEventHubSpan(span, baseData); + assert.strictEqual(baseData.type, `Queue Message | ${attributes[AzNamespace]}`); assert.strictEqual(baseData.target, `${peerAddress}/${destination}`); @@ -111,8 +99,8 @@ describe("#parseEventHubSpan(...)", () => { (span as { startTime: HrTime }).startTime = timeInputToHrTime(startTime); span.setAttributes(attributes); - parseEventHubSpan(span, envelope); const baseData = envelope.data?.baseData as RemoteDependencyData; + parseEventHubSpan(span, baseData); assert.strictEqual(baseData.type, `Queue Message | ${attributes[AzNamespace]}`); assert.strictEqual((baseData as any).source, `${peerAddress}/${destination}`); assert.deepStrictEqual(baseData.measurements, {