Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add namespace for custom metrics #869

Merged
merged 1 commit into from
Nov 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 49 additions & 46 deletions Declarations/Contracts/Generated/DataPoint.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,54 @@
// THIS FILE WAS AUTOGENERATED
import DataPointType = require('./DataPointType');
"use strict";

/**
* Metric data single measurement.
*/
class DataPoint
{

/**
* Name of the metric.
*/
public name: string;

/**
* Metric type. Single measurement or the aggregated value.
*/
public kind: DataPointType;

/**
* Single value for measurement. Sum of individual measurements for the aggregation.
*/
public value: number;

/**
* Metric weight of the aggregated metric. Should not be set for a measurement.
*/
public count: number;

/**
* Minimum value of the aggregated metric. Should not be set for a measurement.
*/
public min: number;

/**
* Maximum value of the aggregated metric. Should not be set for a measurement.
*/
public max: number;

/**
* Standard deviation of the aggregated metric. Should not be set for a measurement.
*/
public stdDev: number;

constructor()
{
this.kind = DataPointType.Measurement;
}

/**
* Metric data single measurement.
*/
class DataPoint {

/**
* Name of the metric.
*/
public name: string;

/**
* Namespace of the metric.
*/
public ns: string;

/**
* Metric type. Single measurement or the aggregated value.
*/
public kind: DataPointType;

/**
* Single value for measurement. Sum of individual measurements for the aggregation.
*/
public value: number;

/**
* Metric weight of the aggregated metric. Should not be set for a measurement.
*/
public count: number;

/**
* Minimum value of the aggregated metric. Should not be set for a measurement.
*/
public min: number;

/**
* Maximum value of the aggregated metric. Should not be set for a measurement.
*/
public max: number;

/**
* Standard deviation of the aggregated metric. Should not be set for a measurement.
*/
public stdDev: number;

constructor() {
this.kind = DataPointType.Measurement;
}
}
export = DataPoint;
5 changes: 5 additions & 0 deletions Declarations/Contracts/TelemetryTypes/MetricTelemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ export interface MetricTelemetry extends Telemetry {
*/
value: number;

/**
* A string that identifies the metric namespace.
*/
namespace?: string;

/**
* Type of metric being sent, e.g. Pre-agg metrics have kind=Aggregation
*/
Expand Down
1 change: 1 addition & 0 deletions Library/EnvelopeFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ class EnvelopeFactory {
metric.name = telemetry.name;
metric.stdDev = !isNaN(telemetry.stdDev) ? telemetry.stdDev : 0;
metric.value = telemetry.value;
metric.ns = telemetry.namespace;

metrics.metrics.push(metric);

Expand Down
68 changes: 48 additions & 20 deletions Tests/Library/EnvelopeFactoryTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ describe("Library/EnvelopeFactory", () => {
var client1 = new Client("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333");
client1.commonProperties = commonproperties;
client1.config.samplingPercentage = 99;
var eventTelemetry = <Contracts.EventTelemetry>{name:"name"};
eventTelemetry.properties = properties;
var eventTelemetry = <Contracts.EventTelemetry>{ name: "name" };
eventTelemetry.properties = properties;
var env = EnvelopeFactory.createEnvelope(eventTelemetry, Contracts.TelemetryType.Event, commonproperties, client1.context, client1.config);

// check sample rate
assert.equal(env.sampleRate, client1.config.samplingPercentage);

var envData:Contracts.Data<Contracts.EventData> = <Contracts.Data<Contracts.EventData>> env.data;
var envData: Contracts.Data<Contracts.EventData> = <Contracts.Data<Contracts.EventData>>env.data;

// check common properties
assert.equal(envData.baseData.properties.common1, (<any>commonproperties).common1);
Expand All @@ -41,20 +41,20 @@ describe("Library/EnvelopeFactory", () => {
it("should allow tags to be overwritten", () => {

var client = new Client("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333");
var env = EnvelopeFactory.createEnvelope(<Contracts.EventTelemetry>{name:"name"}, Contracts.TelemetryType.Event, commonproperties, client.context, client.config);
var env = EnvelopeFactory.createEnvelope(<Contracts.EventTelemetry>{ name: "name" }, Contracts.TelemetryType.Event, commonproperties, client.context, client.config);
assert.deepEqual(env.tags, client.context.tags, "tags are set by default");
var customTag = <{ [id: string]: string }>{ "ai.cloud.roleInstance": "override" };
var expected: { [id: string]: string } = {};
for (var tag in client.context.tags) {
expected[tag] = customTag[tag] || client.context.tags[tag];
}
env = EnvelopeFactory.createEnvelope(<Contracts.EventTelemetry>{name:"name", tagOverrides:customTag}, Contracts.TelemetryType.Event, commonproperties, client.context, client.config);
env = EnvelopeFactory.createEnvelope(<Contracts.EventTelemetry>{ name: "name", tagOverrides: customTag }, Contracts.TelemetryType.Event, commonproperties, client.context, client.config);
assert.deepEqual(env.tags, expected)
});

it("should have valid name", function () {
var client = new Client("key");
var envelope = EnvelopeFactory.createEnvelope(<Contracts.EventTelemetry>{name:"name"}, Contracts.TelemetryType.Event, commonproperties, client.context, client.config);
var envelope = EnvelopeFactory.createEnvelope(<Contracts.EventTelemetry>{ name: "name" }, Contracts.TelemetryType.Event, commonproperties, client.context, client.config);
assert.equal(envelope.name, "Microsoft.ApplicationInsights.key.Event");
});
});
Expand Down Expand Up @@ -107,10 +107,10 @@ describe("Library/EnvelopeFactory", () => {

assert.deepEqual(actual, expected);
});

it("fills stack when provided a scoped package", () => {
simpleError.stack = " at Context.foo (C:/@foo/bar/example.js:123:45)\n" + simpleError.stack;

var envelope = EnvelopeFactory.createEnvelope(<Contracts.ExceptionTelemetry>{ exception: simpleError }, Contracts.TelemetryType.Exception);
var exceptionData = <Contracts.Data<Contracts.ExceptionData>>envelope.data;

Expand All @@ -125,10 +125,10 @@ describe("Library/EnvelopeFactory", () => {
method: "Context.foo"
});
});

it("fills stack when provided a scoped package", () => {
simpleError.stack = " at C:/@foo/bar/example.js:123:45\n" + simpleError.stack;

var envelope = EnvelopeFactory.createEnvelope(<Contracts.ExceptionTelemetry>{ exception: simpleError }, Contracts.TelemetryType.Exception);
var exceptionData = <Contracts.Data<Contracts.ExceptionData>>envelope.data;

Expand Down Expand Up @@ -168,13 +168,13 @@ describe("Library/EnvelopeFactory", () => {
describe("AvailabilityData", () => {
let availabilityTelemetry: Contracts.AvailabilityTelemetry;
beforeEach(() => {
availabilityTelemetry = {
success : true,
availabilityTelemetry = {
success: true,
duration: 100,
measurements: { "m1" : 1},
measurements: { "m1": 1 },
runLocation: "west us",
properties: {
"prop1" : "prop1 value"
"prop1": "prop1 value"
},
message: "availability test message",
name: "availability test name",
Expand All @@ -186,13 +186,13 @@ describe("Library/EnvelopeFactory", () => {
availabilityTelemetry.id = undefined;

var envelope = EnvelopeFactory.createEnvelope(availabilityTelemetry, Contracts.TelemetryType.Availability);
var data = <Contracts.Data<Contracts.AvailabilityData>>envelope.data;
var data = <Contracts.Data<Contracts.AvailabilityData>>envelope.data;
assert.ok(data.baseData.id != null);
});

it("creates data with given content", () => {
var envelope = EnvelopeFactory.createEnvelope(availabilityTelemetry, Contracts.TelemetryType.Availability);
var data = <Contracts.Data<Contracts.AvailabilityData>>envelope.data;
var data = <Contracts.Data<Contracts.AvailabilityData>>envelope.data;

assert.deepEqual(data.baseType, "AvailabilityData");

Expand All @@ -210,11 +210,11 @@ describe("Library/EnvelopeFactory", () => {
describe("PageViewData", () => {
let pageViewTelemetry: Contracts.PageViewTelemetry;
beforeEach(() => {
pageViewTelemetry = {
pageViewTelemetry = {
duration: 100,
measurements: { "m1" : 1},
measurements: { "m1": 1 },
properties: {
"prop1" : "prop1 value"
"prop1": "prop1 value"
},
url: "https://www.test.com",
name: "availability test name",
Expand All @@ -223,7 +223,7 @@ describe("Library/EnvelopeFactory", () => {

it("creates data with given content", () => {
var envelope = EnvelopeFactory.createEnvelope(pageViewTelemetry, Contracts.TelemetryType.PageView);
var data = <Contracts.Data<Contracts.PageViewData>>envelope.data;
var data = <Contracts.Data<Contracts.PageViewData>>envelope.data;

assert.deepEqual(data.baseType, "PageViewData");

Expand All @@ -235,4 +235,32 @@ describe("Library/EnvelopeFactory", () => {

});
});

describe("MetricData", () => {
let metricTelemetry: Contracts.MetricTelemetry;
beforeEach(() => {
metricTelemetry = {
name: "TestName",
value: 123,
namespace: "TestNamespace",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this something we should be adding to the web code as well?
We only have these
export class DataPoint {

/**
 * Name of the metric.
 */
public name: string;

/**
 * Metric type. Single measurement or the aggregated value.
 */
public kind: DataPointType = DataPointType.Measurement;

/**
 * Single value for measurement. Sum of individual measurements for the aggregation.
 */
public value: number;

/**
 * Metric weight of the aggregated metric. Should not be set for a measurement.
 */
public count: number;

/**
 * Minimum value of the aggregated metric. Should not be set for a measurement.
 */
public min: number;

/**
 * Maximum value of the aggregated metric. Should not be set for a measurement.
 */
public max: number;

/**
 * Standard deviation of the aggregated metric. Should not be set for a measurement.
 */
public stdDev: number;

}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you should, "ns" is the actual field we put in the envelope, namespace is the property name of the class we expose in the API

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, will raise an issue on AI-JS

count: 456,
min: 1,
max: 8,
stdDev: 4
};
});

it("creates data with given content", () => {
var envelope = EnvelopeFactory.createEnvelope(metricTelemetry, Contracts.TelemetryType.Metric);
var data = <Contracts.Data<Contracts.MetricData>>envelope.data;

assert.deepEqual(data.baseType, "MetricData");
assert.deepEqual(data.baseData.metrics[0].name, metricTelemetry.name);
assert.deepEqual(data.baseData.metrics[0].value, metricTelemetry.value);
assert.deepEqual(data.baseData.metrics[0].ns, metricTelemetry.namespace);
assert.deepEqual(data.baseData.metrics[0].min, metricTelemetry.min);
assert.deepEqual(data.baseData.metrics[0].max, metricTelemetry.max);
assert.deepEqual(data.baseData.metrics[0].stdDev, metricTelemetry.stdDev);
});
});
});