first commit

This commit is contained in:
Stefan Hacker
2026-04-03 09:38:48 +02:00
commit 37ad745546
47450 changed files with 3120798 additions and 0 deletions
+25
View File
@@ -0,0 +1,25 @@
name: Back Compatibility CI
on:
push:
branches: [ develop, master ]
pull_request:
branches: [ develop, master ]
jobs:
backcompat:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run backcompattest
+25
View File
@@ -0,0 +1,25 @@
name: Integration Tests CI
on:
push:
branches: [ develop, master ]
pull_request:
branches: [ develop, master ]
jobs:
integration:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [10.x, 12.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run functionaltest
+27
View File
@@ -0,0 +1,27 @@
name: Node.js CI
on:
push:
branches: [ develop, master ]
pull_request:
branches: [ develop, master ]
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
node-version: [8.x, 10.x, 12.x, 14.x]
steps:
- uses: actions/checkout@v2
- name: (${{ matrix.os }}) on Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run build --if-present
- run: npm test
+35
View File
@@ -0,0 +1,35 @@
# This workflow will run tests using node and then publish a package to npm when a release is created
# For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages
name: Node.js Package
on:
push:
branches: [applicationinsights@2.0.0]
release:
types: [created]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12
- run: npm ci
- run: npm test
publish-npm:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12
registry-url: https://registry.npmjs.org/
- run: npm ci
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
+8
View File
@@ -0,0 +1,8 @@
The MIT License (MIT)
Copyright © Microsoft Corporation
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+549
View File
@@ -0,0 +1,549 @@
# Application Insights for Node.js
[![npm version](https://badge.fury.io/js/applicationinsights.svg)](http://badge.fury.io/js/applicationinsights)
[![Build Status](https://travis-ci.org/Microsoft/ApplicationInsights-node.js.svg?branch=master)](https://travis-ci.org/Microsoft/ApplicationInsights-node.js)
![Integration Tests CI](https://github.com/microsoft/ApplicationInsights-node.js/workflows/Integration%20Tests%20CI/badge.svg)
![Node.js CI](https://github.com/microsoft/ApplicationInsights-node.js/workflows/Node.js%20CI/badge.svg)
![Back Compatability CI](https://github.com/microsoft/ApplicationInsights-node.js/workflows/Back%20Compatability%20CI/badge.svg)
[Azure Application Insights][] monitors your backend services and components after
you deploy them to help you [discover and rapidly diagnose performance and other
issues][]. Add this SDK to your Node.js services to include deep info about Node.js
processes and their external dependencies such as database and cache services.
You can use this SDK for your Node.js services hosted anywhere: your datacenter,
Azure VMs and Web Apps, and even other public clouds.
[Azure Application Insights]: https://azure.microsoft.com/documentation/articles/app-insights-overview/
[discover and rapidly diagnose performance and other issues]: https://docs.microsoft.com/azure/application-insights/app-insights-detect-triage-diagnose
This library tracks the following out-of-the-box:
- Incoming and outgoing HTTP requests
- Important system metrics such as CPU usage
- Unhandled exceptions
- Events from many popular third-party libraries ([see Automatic third-party instrumentation](#automatic-third-party-instrumentation))
You can manually track more aspects of your app and system using the API described in the
[Track custom telemetry](#track-custom-telemetry) section.
## Getting Started
1. Create an Application Insights resource in Azure by following [these instructions][].
2. Grab the _Instrumentation Key_ (aka "ikey") from the resource you created in
step 1. Later, you'll either add it to your app's environment variables or
use it directly in your scripts.
3. Add the Application Insights Node.js SDK to your app's dependencies and
package.json:
```bash
npm install --save applicationinsights
```
> *Note:* If you're using TypeScript, do not install a separate "typings" package.
> This NPM package contains built-in typings.
4. As early as possible in your app's code, load the Application Insights
package:
```javascript
let appInsights = require('applicationinsights');
```
5. Configure the local SDK by calling `appInsights.setup('_your_ikey_');`, using
the ikey you grabbed in step 2. Or put this ikey in the
`APPINSIGHTS_INSTRUMENTATIONKEY` environment variable and call
`appInsights.setup()` without parameters.
> For more configuration options see below.
6. Finally, start automatically collecting and sending data by calling
`appInsights.start();`.
[these instructions]: https://docs.microsoft.com/azure/application-insights/app-insights-nodejs
## Basic Usage
> *Important:* `applicationinsights` must be setup *and* started *before* you import anything else. There may be resulting telemetry loss if other libraries are imported first.
For out-of-the-box collection of HTTP requests, popular third-party library events,
unhandled exceptions, and system metrics:
```javascript
let appInsights = require("applicationinsights");
appInsights.setup("_your_ikey_").start();
```
* If the instrumentation key is set in the environment variable
APPINSIGHTS\_INSTRUMENTATIONKEY, `.setup()` can be called with no
arguments. This makes it easy to use different ikeys for different
environments.
Load the Application Insights library (i.e. `require("applicationinsights")`) as
early as possible in your scripts, before loading other packages. This is needed
so that the Application Insights library can prepare later packages for tracking.
If you encounter conflicts with other libraries doing similar preparation, try
loading the Application Insights library after those.
Because of the way JavaScript handles callbacks, additional work is necessary to
track a request across external dependencies and later callbacks. By default
this additional tracking is enabled; disable it by calling
`setAutoDependencyCorrelation(false)` as described in the
Configuration section below.
## Azure Functions
Due to how Azure Functions (and other FaaS services) handle incoming requests, they are not seen as `http` requests to the Node.js runtime. For this reason, Request -> Dependency correlelation will **not** work out of the box.
To enable tracking here, you simply need to grab the context from your Function request handler, and wrap your Function with that context.
### Setting up Auto-Correlation for Azure Functions
You do not need to make any changes to your existing Function logic.
Instead, you can update the `default` export of your `httpTrigger` to be wrapped with some Application Insights logic:
```js
...
// Default export wrapped with Application Insights FaaS context propagation
export default async function contextPropagatingHttpTrigger(context, req) {
// Start an AI Correlation Context using the provided Function context
const correlationContext = appInsights.startOperation(context, req);
// Wrap the Function runtime with correlationContext
return appInsights.wrapWithCorrelationContext(async () => {
const startTime = Date.now(); // Start trackRequest timer
// Run the Function
await httpTrigger(context, req);
// Track Request on completion
appInsights.defaultClient.trackRequest({
name: context.req.method + " " + context.req.url,
resultCode: context.res.status,
success: true,
url: req.url,
duration: Date.now() - startTime,
id: correlationContext.operation.parentId,
});
appInsights.defaultClient.flush();
}, correlationContext)();
};
```
### Azure Functions Example
An example of making an `axios` call to <https://httpbin.org> and returning the reponse.
```js
const appInsights = require("applicationinsights");
appInsights.setup("ikey")
.setAutoCollectPerformance(false)
.start();
const axios = require("axios");
/**
* No changes required to your existing Function logic
*/
const httpTrigger = async function (context, req) {
const response = await axios.get("https://httpbin.org/status/200");
context.res = {
status: response.status,
body: response.statusText,
};
};
// Default export wrapped with Application Insights FaaS context propagation
export default async function contextPropagatingHttpTrigger(context, req) {
// Start an AI Correlation Context using the provided Function context
const correlationContext = appInsights.startOperation(context, req);
// Wrap the Function runtime with correlationContext
return appInsights.wrapWithCorrelationContext(async () => {
const startTime = Date.now(); // Start trackRequest timer
// Run the Function
await httpTrigger(context, req);
// Track Request on completion
appInsights.defaultClient.trackRequest({
name: context.req.method + " " + context.req.url,
resultCode: context.res.status,
success: true,
url: req.url,
duration: Date.now() - startTime,
id: correlationContext.operation.parentId,
});
appInsights.defaultClient.flush();
}, correlationContext)();
};
```
## Configuration
The appInsights object provides a number of configuration methods. They are
listed in the following snippet with their default values.
```javascript
let appInsights = require("applicationinsights");
appInsights.setup("<instrumentation_key>")
.setAutoDependencyCorrelation(true)
.setAutoCollectRequests(true)
.setAutoCollectPerformance(true, true)
.setAutoCollectExceptions(true)
.setAutoCollectDependencies(true)
.setAutoCollectConsole(true)
.setUseDiskRetryCaching(true)
.setSendLiveMetrics(false)
.setDistributedTracingMode(appInsights.DistributedTracingModes.AI_AND_W3C)
.start();
```
Please review their descriptions in your IDE's built-in type hinting, or [applicationinsights.ts](https://github.com/microsoft/ApplicationInsights-node.js/tree/develop/applicationinsights.ts) for
detailed information on what these control, and optional secondary arguments.
Note that by default `setAutoCollectConsole` is configured to *exclude* calls to `console.log`
(and other `console` methods). By default, only calls to supported third-party loggers
(e.g. `winston`, `bunyan`) will be collected. You can change this behavior to *include* calls
to `console` methods by using `setAutoCollectConsole(true, true)`.
### Sampling
By default, the SDK will send all collected data to the Application Insights service. If you collect a lot of data, you might want to enable sampling to reduce the amount of data sent. Set the `samplingPercentage` field on the Config object of a Client to accomplish this. Setting `samplingPercentage` to 100 (the default) means all data will be sent, and 0 means nothing will be sent.
If you are using automatic correlation, all data associated with a single request will be included or excluded as a unit.
Add code such as the following to enable sampling:
```javascript
const appInsights = require("applicationinsights");
appInsights.setup("<instrumentation_key>");
appInsights.defaultClient.config.samplingPercentage = 33; // 33% of all telemetry will be sent to Application Insights
appInsights.start();
```
### Multiple roles for multi-component applications
If your application consists of multiple components that you wish to instrument all with the same Instrumentation Key and still see these components as separate units in the Portal as if they were using separate Instrumentation Keys (for example, as separate nodes on the Application Map) you may need to manually configure the RoleName field to distinguish one component's telemetry from other components sending data to your Application Insights resource. (See [Monitor multi-component applications with Application Insights (preview)](https://docs.microsoft.com/azure/application-insights/app-insights-monitor-multi-role-apps))
Use the following to set the RoleName field:
```javascript
const appInsights = require("applicationinsights");
appInsights.setup("<instrumentation_key>");
appInsights.defaultClient.context.tags[appInsights.defaultClient.context.keys.cloudRole] = "MyRoleName";
appInsights.start();
```
If running in Azure App service or Azure functions the SDK will automatically populate the cloud role when following code is added:
```javascript
const appInsights = require("applicationinsights");
appInsights.setup("<instrumentation_key>");
appInsights.defaultClient.setAutoPopulateAzureProperties(true);
appInsights.start();
```
### Automatic third-party instrumentation
In order to track context across asynchronous calls, some changes are required in third party libraries such as mongodb and redis.
By default ApplicationInsights will use [`diagnostic-channel-publishers`](https://github.com/microsoft/node-diagnostic-channel/tree/master/src/diagnostic-channel-publishers)
to monkey-patch some of these libraries.
This can be disabled by setting the `APPLICATION_INSIGHTS_NO_DIAGNOSTIC_CHANNEL` environment variable. Note that by setting that
environment variable, events may no longer be correctly associated with the right operation. Individual monkey-patches can be
disabled by setting the `APPLICATION_INSIGHTS_NO_PATCH_MODULES` environment variable to a comma separated list of packages to
disable, e.g. `APPLICATION_INSIGHTS_NO_PATCH_MODULES=console,redis` to avoid patching the `console` and `redis` packages.
Currently there are 9 packages which are instrumented: `bunyan`, `console`, `mongodb`, `mongodb-core`, `mysql`, `redis`, `winston`,
`pg`, and `pg-pool`. Visit the [diagnostic-channel-publishers' README](https://github.com/microsoft/node-diagnostic-channel/blob/master/src/diagnostic-channel-publishers/README.md)
for information about exactly which versions of these packages are patched.
The `bunyan`, `winston`, and `console` patches will generate Application Insights Trace events based on whether `setAutoCollectConsole` is enabled.
The rest will generate Application Insights Dependency events based on whether `setAutoCollectDependencies` is enabled. Make sure that `applicationinsights` is imported **before** any 3rd-party packages for them to be instrumented successfully.
Automatic instrumentation for several Azure SDKs is also available, you must manually install @opentelemetry/tracing to enable this automatic tracing. No additional configuration is required
Currently Cognitive Search, Communication Common and Cosmos DB SDKs are not supported.
[Javascript Azure SDKs](https://azure.github.io/azure-sdk/releases/latest/index.html#javascript)
### Live Metrics
To enable sending live metrics of your app to Azure, use `setSendLiveMetrics(true)`. Filtering of live metrics in the Portal is currently not supported.
### Extended Metrics
>***Note:*** The ability to send extended native metrics was added in version `1.4.0`
To enable sending extended native metrics of your app to Azure, simply install the separate native metrics package. The SDK will automatically load it when it is installed and start collecting Node.js native metrics.
```zsh
npm install applicationinsights-native-metrics
```
Currently, the native metrics package performs autocollection of Garbage Collection CPU time, Event Loop ticks, and heap usage:
- **Garbage Collection:** The amount of CPU time spent on each type of garbage collection, and how many occurrences of each type.
- **Event Loop:** How many ticks occurred and how much CPU time was spent in total.
- **Heap vs Non-Heap:** How much of your app's memory usage is in the heap or non-heap.
### Distributed Tracing Modes
By default, this SDK will send headers understood by other applications/services instrumented with an Application Insights SDK. You can optionally enable sending/receiving of [W3C Trace Context](https://github.com/w3c/trace-context) headers in addition to the existing AI headers, so you will not break correlation with any of your existing legacy services. Enabling W3C headers will allow your app to correlate with other services not instrumented with Application Insights, but do adopt this W3C standard.
```js
const appInsights = require("applicationinsights");
appInsights
.setup("<your ikey>")
.setDistributedTracingMode(appInsights.DistributedTracingModes.AI_AND_W3C)
.start()
```
## Track custom telemetry
You can track any request, event, metric or exception using the Application
Insights client. Examples follow:
```javascript
let appInsights = require("applicationinsights");
appInsights.setup().start(); // assuming ikey in env var. start() can be omitted to disable any non-custom data
let client = appInsights.defaultClient;
client.trackEvent({name: "my custom event", properties: {customProperty: "custom property value"}});
client.trackException({exception: new Error("handled exceptions can be logged with this method")});
client.trackMetric({name: "custom metric", value: 3});
client.trackTrace({message: "trace message"});
client.trackDependency({target:"http://dbname", name:"select customers proc", data:"SELECT * FROM Customers", duration:231, resultCode:0, success: true, dependencyTypeName: "ZSQL"});
client.trackRequest({name:"GET /customers", url:"http://myserver/customers", duration:309, resultCode:200, success:true});
let http = require("http");
http.createServer( (req, res) => {
client.trackNodeHttpRequest({request: req, response: res}); // Place at the beginning of your request handler
});
```
Note that custom properties are converted to their string representation before being sent, see [Using properties](https://docs.microsoft.com/azure/azure-monitor/app/api-custom-events-metrics#properties) for more information.
An example utility using `trackMetric` to measure how long event loop scheduling takes:
```javascript
function startMeasuringEventLoop() {
var startTime = process.hrtime();
var sampleSum = 0;
var sampleCount = 0;
// Measure event loop scheduling delay
setInterval(() => {
var elapsed = process.hrtime(startTime);
startTime = process.hrtime();
sampleSum += elapsed[0] * 1e9 + elapsed[1];
sampleCount++;
}, 0);
// Report custom metric every second
setInterval(() => {
var samples = sampleSum;
var count = sampleCount;
sampleSum = 0;
sampleCount = 0;
if (count > 0) {
var avgNs = samples / count;
var avgMs = Math.round(avgNs / 1e6);
client.trackMetric({name: "Event Loop Delay", value: avgMs});
}
}, 1000);
}
```
## Preprocess data with Telemetry Processors
```javascript
public addTelemetryProcessor(telemetryProcessor: (envelope: Contracts.Envelope, context: { http.RequestOptions, http.ClientRequest, http.ClientResponse, correlationContext }) => boolean)
```
You can process and filter collected data before it is sent for retention using
_Telemetry Processors_. Telemetry processors are called one by one in the
order they were added before the telemetry item is sent to the cloud.
If a telemetry processor returns false that telemetry item will not be sent.
All telemetry processors receive the telemetry data and its envelope to inspect and
modify. They also receive a context object. The contents of this object is defined by
the `contextObjects` parameter when calling a track method for manually tracked telemetry.
For automatically collected telemetry, this object is filled with available request information
and the persistent request context as provided by `appInsights.getCorrelationContext()` (if
automatic dependency correlation is enabled).
The TypeScript type for a telemetry processor is:
```typescript
telemetryProcessor: (envelope: ContractsModule.Contracts.Envelope, context: { http.RequestOptions, http.ClientRequest, http.ClientResponse, correlationContext }) => boolean;
```
For example, a processor that removes stack trace data from exceptions might be
written and added as follows:
```javascript
function removeStackTraces ( envelope, context ) {
if (envelope.data.baseType === "ExceptionData") {
var data = envelope.data.baseData;
if (data.exceptions && data.exceptions.length > 0) {
for (var i = 0; i < data.exceptions.length; i++) {
var exception = data.exceptions[i];
exception.parsedStack = null;
exception.hasFullStack = false;
}
}
}
return true;
}
appInsights.defaultClient.addTelemetryProcessor(removeStackTraces);
```
More info on the telemetry API is available in [the docs][].
[the docs]: https://azure.microsoft.com/documentation/articles/app-insights-api-custom-events-metrics/
## Use multiple instrumentation keys
You can create multiple Azure Application Insights resources and send different
data to each by using their respective instrumentation keys ("ikey"). For
example:
```javascript
let appInsights = require("applicationinsights");
// configure auto-collection under one ikey
appInsights.setup("_ikey-A_").start();
// track some events manually under another ikey
let otherClient = new appInsights.TelemetryClient("_ikey-B_");
otherClient.trackEvent({name: "my custom event"});
```
## Examples
* Track dependencies
```javascript
let appInsights = require("applicationinsights");
let client = new appInsights.TelemetryClient();
var success = false;
let startTime = Date.now();
// execute dependency call here....
let duration = Date.now() - startTime;
success = true;
client.trackDependency({target:"http://dbname", name:"select customers proc", data:"SELECT * FROM Customers", duration:duration, resultCode:0, success: true, dependencyTypeName: "ZSQL"});
```
* Assign custom properties to be included with all events
```javascript
appInsights.defaultClient.commonProperties = {
environment: process.env.SOME_ENV_VARIABLE
};
```
* Manually track all HTTP GET requests
Note that all requests are tracked by default. To disable automatic
collection, call `.setAutoCollectRequests(false)` before calling `start()`.
```javascript
appInsights.defaultClient.trackRequest({name:"GET /customers", url:"http://myserver/customers", duration:309, resultCode:200, success:true});
```
Alternatively you can track requests using ```trackNodeHttpRequest``` method:
```javascript
var server = http.createServer((req, res) => {
if ( req.method === "GET" ) {
appInsights.defaultClient.trackNodeHttpRequest({request:req, response:res});
}
// other work here....
res.end();
});
```
* Track server startup time
```javascript
let start = Date.now();
server.on("listening", () => {
let duration = Date.now() - start;
appInsights.defaultClient.trackMetric({name: "server startup time", value: duration});
});
```
## Advanced configuration options
The Client object contains a `config` property with many optional settings for
advanced scenarios. These can be set as follows:
```
client.config.PROPERTYNAME = VALUE;
```
These properties are client specific, so you can configure `appInsights.defaultClient`
separately from clients created with `new appInsights.TelemetryClient()`.
| Property | Description |
| ------------------------------- |------------------------------------------------------------------------------------------------------------|
| instrumentationKey | An identifier for your Application Insights resource |
| endpointUrl | The ingestion endpoint to send telemetry payloads to |
| quickPulseHost | The Live Metrics Stream host to send live metrics telemetry to |
| proxyHttpUrl | A proxy server for SDK HTTP traffic (Optional, Default pulled from `http_proxy` environment variable) |
| proxyHttpsUrl | A proxy server for SDK HTTPS traffic (Optional, Default pulled from `https_proxy` environment variable) |
| httpAgent | An http.Agent to use for SDK HTTP traffic (Optional, Default undefined) |
| httpsAgent | An https.Agent to use for SDK HTTPS traffic (Optional, Default undefined) |
| maxBatchSize | The maximum number of telemetry items to include in a payload to the ingestion endpoint (Default `250`) |
| maxBatchIntervalMs | The maximum amount of time to wait to for a payload to reach maxBatchSize (Default `15000`) |
| disableAppInsights | A flag indicating if telemetry transmission is disabled (Default `false`) |
| samplingPercentage | The percentage of telemetry items tracked that should be transmitted (Default `100`) |
| correlationIdRetryIntervalMs | The time to wait before retrying to retrieve the id for cross-component correlation (Default `30000`) |
| correlationHeaderExcludedDomains| A list of domains to exclude from cross-component correlation header injection (Default See [Config.ts][]) |
[Config.ts]: https://github.com/microsoft/ApplicationInsights-node.js/blob/develop/Library/Config.ts
## Migrating to [`applicationinsights@2.0.0`](https://github.com/microsoft/ApplicationInsights-node.js/tree/applicationinsights%402.0.0) (Beta)
An experimental / beta version of the SDK is also available, but not recommended for production. It is built on top of the [OpenTelemetry SDK + APIs](http://github.com/open-telemetry/opentelemetry-js), while keeping the API surface of this SDK the same.
```zsh
npm install applicationinsights@beta
```
### `applicationinsights@2.0.0` Overview
- Autocollection parity with `applicationinsights@1.x`
- API parity with `applicationinsights@1.x`
- "Getting Started" parity with `applicationinsights@1.x`
- New autocollection scenarios out-of-the-box contribued by the [OpenTelemetry community](https://github.com/open-telemetry/opentelemetry-js#node-plugins), e.g. `gRPC`, `express`, `ioredis`
- Built on top of an [Open Standard](https://github.com/open-telemetry/opentelemetry-specification) for Telemetry APIs and SDKs
Migrating from `1.x` to `2.x` is meant to be seamless and straightforward, there should be no breaking API changes at all. Please file a bug if something doesn't look right to you!
Included in `applicationinsights@2.0.0` is [every Node.js Plugin available in the default OpenTelemetry Node.js SDK](https://github.com/open-telemetry/opentelemetry-js#node-plugins). Please check out the [projects board](https://github.com/microsoft/ApplicationInsights-node.js/projects) for progress updates on `2.x`.
## Branches
- Ongoing development takes place on the [develop][] branch. **Please submit
pull requests to this branch.**
- Releases are merged to the [master][] branch and published to [npm][].
[master]: https://github.com/microsoft/ApplicationInsights-node.js/tree/master
[develop]: https://github.com/microsoft/ApplicationInsights-node.js/tree/develop
[npm]: https://www.npmjs.com/package/applicationinsights
## Contributing
1. Install all dependencies with `npm install`.
2. Set an environment variable to your instrumentation key (optional).
```bash
// windows
set APPINSIGHTS_INSTRUMENTATIONKEY=<insert_your_instrumentation_key_here>
// linux/macos
export APPINSIGHTS_INSTRUMENTATIONKEY=<insert_your_instrumentation_key_here>
```
3. Run tests
```bash
npm run test
npm run backcompattest
npm run functionaltest
```
_Note: Functional tests require Docker_
---
This project has adopted the [Microsoft Open Source Code of Conduct][]. For more
information see the [Code of Conduct FAQ][] or contact
[opencode@microsoft.com][] with any additional questions or comments.
[Microsoft Open Source Code of Conduct]: https://opensource.microsoft.com/codeofconduct/
[Code of Conduct FAQ]: https://opensource.microsoft.com/codeofconduct/faq/
[opencode@microsoft.com]: mailto:opencode@microsoft.com
@@ -0,0 +1,72 @@
/**
* Type of span. Can be used to specify additional relationships between spans
* in addition to a parent/child relationship.
*/
export declare enum SpanKind {
/** Default value. Indicates that the span is used internally. */
INTERNAL = 0,
/**
* Indicates that the span covers server-side handling of an RPC or other
* remote request.
*/
SERVER = 1,
/**
* Indicates that the span covers the client-side wrapper around an RPC or
* other remote request.
*/
CLIENT = 2,
/**
* Indicates that the span describes producer sending a message to a
* broker. Unlike client and server, there is no direct critical path latency
* relationship between producer and consumer spans.
*/
PRODUCER = 3,
/**
* Indicates that the span describes consumer receiving a message from a
* broker. Unlike client and server, there is no direct critical path latency
* relationship between producer and consumer spans.
*/
CONSUMER = 4,
}
export declare type LinkContext = Pick<SpanContext, 'traceId' | 'spanId'>;
export interface Attributes {
[attributeKey: string]: AttributeValue | undefined;
}
export declare type AttributeValue = string | number | boolean | Array<null | undefined | string> | Array<null | undefined | number> | Array<null | undefined | boolean>;
export interface Link {
/** The {@link SpanContext} of a linked span. */
context: LinkContext;
/** A set of {@link Attributes} on the link. */
attributes?: Attributes;
}
export interface SpanContext {
traceId: string;
spanId: string;
traceFlags?: {
toString: () => string;
};
tracestate?: string;
}
export interface Span {
_duration: [number, number];
name: string;
parentSpanId?: string;
status: {
code: number;
message?: string;
};
attributes: Record<string, string>;
kind: SpanKind;
links: Link[];
context: () => SpanContext;
}
export declare class OpenTelemetryScopeManagerWrapper {
private _activeSymbol;
active(): any;
with(span: Span, fn: () => any): any;
bind<T>(target: T): T;
enable(): this;
disable(): this;
private static _spanToContext(span, parentSpanId?, name?);
}
export declare const AsyncScopeManager: OpenTelemetryScopeManagerWrapper;
@@ -0,0 +1,95 @@
"use strict";
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
var CorrelationContextManager_1 = require("./CorrelationContextManager");
var events_1 = require("events");
/**
* Type of span. Can be used to specify additional relationships between spans
* in addition to a parent/child relationship.
*/
var SpanKind;
(function (SpanKind) {
/** Default value. Indicates that the span is used internally. */
SpanKind[SpanKind["INTERNAL"] = 0] = "INTERNAL";
/**
* Indicates that the span covers server-side handling of an RPC or other
* remote request.
*/
SpanKind[SpanKind["SERVER"] = 1] = "SERVER";
/**
* Indicates that the span covers the client-side wrapper around an RPC or
* other remote request.
*/
SpanKind[SpanKind["CLIENT"] = 2] = "CLIENT";
/**
* Indicates that the span describes producer sending a message to a
* broker. Unlike client and server, there is no direct critical path latency
* relationship between producer and consumer spans.
*/
SpanKind[SpanKind["PRODUCER"] = 3] = "PRODUCER";
/**
* Indicates that the span describes consumer receiving a message from a
* broker. Unlike client and server, there is no direct critical path latency
* relationship between producer and consumer spans.
*/
SpanKind[SpanKind["CONSUMER"] = 4] = "CONSUMER";
})(SpanKind = exports.SpanKind || (exports.SpanKind = {}));
var OpenTelemetryScopeManagerWrapper = (function () {
function OpenTelemetryScopeManagerWrapper() {
}
OpenTelemetryScopeManagerWrapper.prototype.active = function () {
var _this = this;
var context = CorrelationContextManager_1.CorrelationContextManager.getCurrentContext();
return __assign({}, context, { getValue: function (key) {
// todo: lazy import activeSymbol from opentelemetry/api
if (!_this._activeSymbol) {
_this._activeSymbol = key;
return context;
}
if (key === _this._activeSymbol) {
return context;
}
return false;
}, setValue: function () { } });
};
OpenTelemetryScopeManagerWrapper.prototype.with = function (span, fn) {
var parentSpanId = span.parentSpanId;
var name = span.name;
var correlationContext = OpenTelemetryScopeManagerWrapper._spanToContext(span, parentSpanId, name);
return CorrelationContextManager_1.CorrelationContextManager.runWithContext(correlationContext, fn)();
};
OpenTelemetryScopeManagerWrapper.prototype.bind = function (target) {
if (typeof target === "function") {
return CorrelationContextManager_1.CorrelationContextManager.wrapCallback(target);
}
else if (target instanceof events_1.EventEmitter) {
CorrelationContextManager_1.CorrelationContextManager.wrapEmitter(target);
}
return target;
};
OpenTelemetryScopeManagerWrapper.prototype.enable = function () {
CorrelationContextManager_1.CorrelationContextManager.enable();
return this;
};
OpenTelemetryScopeManagerWrapper.prototype.disable = function () {
CorrelationContextManager_1.CorrelationContextManager.disable();
return this;
};
OpenTelemetryScopeManagerWrapper._spanToContext = function (span, parentSpanId, name) {
var _parentId = parentSpanId ? "|" + span.context().traceId + "." + parentSpanId + "." : span.context().traceId;
var context = __assign({}, span.context(), { traceFlags: span.context().traceFlags.toString() });
var correlationContext = CorrelationContextManager_1.CorrelationContextManager.spanToContextObject(context, _parentId, name);
return correlationContext;
};
return OpenTelemetryScopeManagerWrapper;
}());
exports.OpenTelemetryScopeManagerWrapper = OpenTelemetryScopeManagerWrapper;
exports.AsyncScopeManager = new OpenTelemetryScopeManagerWrapper();
//# sourceMappingURL=AsyncHooksScopeManager.js.map
File diff suppressed because one or more lines are too long
+15
View File
@@ -0,0 +1,15 @@
import TelemetryClient = require("../Library/TelemetryClient");
declare class AutoCollectConsole {
static originalMethods: {
[name: string]: (message?: any, ...optionalParams: any[]) => void;
};
static INSTANCE: AutoCollectConsole;
private static _methodNames;
private _client;
private _isInitialized;
constructor(client: TelemetryClient);
enable(isEnabled: boolean, collectConsoleLog: boolean): void;
isInitialized(): boolean;
dispose(): void;
}
export = AutoCollectConsole;
+29
View File
@@ -0,0 +1,29 @@
"use strict";
var DiagChannel = require("./diagnostic-channel/initialization");
var AutoCollectConsole = (function () {
function AutoCollectConsole(client) {
if (!!AutoCollectConsole.INSTANCE) {
throw new Error("Console logging adapter tracking should be configured from the applicationInsights object");
}
this._client = client;
AutoCollectConsole.INSTANCE = this;
}
AutoCollectConsole.prototype.enable = function (isEnabled, collectConsoleLog) {
if (DiagChannel.IsInitialized) {
require("./diagnostic-channel/console.sub").enable(isEnabled && collectConsoleLog, this._client);
require("./diagnostic-channel/bunyan.sub").enable(isEnabled, this._client);
require("./diagnostic-channel/winston.sub").enable(isEnabled, this._client);
}
};
AutoCollectConsole.prototype.isInitialized = function () {
return this._isInitialized;
};
AutoCollectConsole.prototype.dispose = function () {
AutoCollectConsole.INSTANCE = null;
this.enable(false, false);
};
AutoCollectConsole._methodNames = ["debug", "info", "log", "warn", "error"];
return AutoCollectConsole;
}());
module.exports = AutoCollectConsole;
//# sourceMappingURL=Console.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"Console.js","sourceRoot":"","sources":["../../AutoCollection/Console.ts"],"names":[],"mappings":";AAGA,iEAAmE;AAEnE;IASI,4BAAY,MAAuB;QAC/B,EAAE,CAAA,CAAC,CAAC,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,2FAA2F,CAAC,CAAC;QACjH,CAAC;QAED,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,kBAAkB,CAAC,QAAQ,GAAG,IAAI,CAAC;IACvC,CAAC;IAEM,mCAAM,GAAb,UAAc,SAAkB,EAAE,iBAA0B;QACxD,EAAE,CAAC,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC;YAC5B,OAAO,CAAC,kCAAkC,CAAC,CAAC,MAAM,CAAC,SAAS,IAAI,iBAAiB,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YACjG,OAAO,CAAC,iCAAiC,CAAC,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YAC3E,OAAO,CAAC,kCAAkC,CAAC,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAChF,CAAC;IACL,CAAC;IAEM,0CAAa,GAApB;QACI,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC;IAC/B,CAAC;IAEM,oCAAO,GAAd;QACI,kBAAkB,CAAC,QAAQ,GAAG,IAAI,CAAC;QACnC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC9B,CAAC;IA7Bc,+BAAY,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IA8B5E,yBAAC;CAAA,AAlCD,IAkCC;AAED,iBAAS,kBAAkB,CAAC","sourcesContent":["import TelemetryClient = require(\"../Library/TelemetryClient\");\r\nimport Logging = require(\"../Library/Logging\");\r\n\r\nimport * as DiagChannel from \"./diagnostic-channel/initialization\";\r\n\r\nclass AutoCollectConsole {\r\n public static originalMethods: {[name: string]: (message?: any, ...optionalParams: any[]) => void};\r\n\r\n public static INSTANCE: AutoCollectConsole;\r\n private static _methodNames = [\"debug\", \"info\", \"log\", \"warn\", \"error\"];\r\n\r\n private _client: TelemetryClient;\r\n private _isInitialized: boolean;\r\n\r\n constructor(client: TelemetryClient) {\r\n if(!!AutoCollectConsole.INSTANCE) {\r\n throw new Error(\"Console logging adapter tracking should be configured from the applicationInsights object\");\r\n }\r\n\r\n this._client = client;\r\n AutoCollectConsole.INSTANCE = this;\r\n }\r\n\r\n public enable(isEnabled: boolean, collectConsoleLog: boolean) {\r\n if (DiagChannel.IsInitialized) {\r\n require(\"./diagnostic-channel/console.sub\").enable(isEnabled && collectConsoleLog, this._client);\r\n require(\"./diagnostic-channel/bunyan.sub\").enable(isEnabled, this._client);\r\n require(\"./diagnostic-channel/winston.sub\").enable(isEnabled, this._client);\r\n }\r\n }\r\n\r\n public isInitialized() {\r\n return this._isInitialized;\r\n }\r\n\r\n public dispose() {\r\n AutoCollectConsole.INSTANCE = null;\r\n this.enable(false, false);\r\n }\r\n}\r\n\r\nexport = AutoCollectConsole;\r\n"]}
@@ -0,0 +1,101 @@
/// <reference types="node" />
import events = require("events");
import * as azureFunctionsTypes from "../Library/Functions";
import * as http from "http";
import Traceparent = require("../Library/Traceparent");
import Tracestate = require("../Library/Tracestate");
import { ISpanContext } from "diagnostic-channel";
export interface CustomProperties {
/**
* Get a custom property from the correlation context
*/
getProperty(key: string): string;
/**
* Store a custom property in the correlation context.
* Do not store sensitive information here.
* Properties stored here are exposed via outgoing HTTP headers for correlating data cross-component.
* The characters ',' and '=' are disallowed within keys or values.
*/
setProperty(key: string, value: string): void;
}
export interface PrivateCustomProperties extends CustomProperties {
addHeaderData(header: string): void;
serializeToHeader(): string;
}
export interface CorrelationContext {
operation: {
name: string;
id: string;
parentId: string;
traceparent?: Traceparent;
tracestate?: Tracestate;
};
/** Do not store sensitive information here.
* Properties here are exposed via outgoing HTTP headers for correlating data cross-component.
*/
customProperties: CustomProperties;
}
export declare class CorrelationContextManager {
private static enabled;
private static hasEverEnabled;
private static forceClsHooked;
private static session;
private static cls;
private static CONTEXT_NAME;
/**
* Provides the current Context.
* The context is the most recent one entered into for the current
* logical chain of execution, including across asynchronous calls.
*/
static getCurrentContext(): CorrelationContext | null;
/**
* A helper to generate objects conforming to the CorrelationContext interface
*/
static generateContextObject(operationId: string, parentId?: string, operationName?: string, correlationContextHeader?: string, traceparent?: Traceparent, tracestate?: Tracestate): CorrelationContext;
static spanToContextObject(spanContext: ISpanContext, parentId?: string, name?: string): CorrelationContext;
/**
* Runs a function inside a given Context.
* All logical children of the execution path that entered this Context
* will receive this Context object on calls to GetCurrentContext.
*/
static runWithContext(context: CorrelationContext, fn: () => any): any;
/**
* Wrapper for cls-hooked bindEmitter method
*/
static wrapEmitter(emitter: events.EventEmitter): void;
/**
* Patches a callback to restore the correct Context when getCurrentContext
* is run within it. This is necessary if automatic correlation fails to work
* with user-included libraries.
*
* The supplied callback will be given the same context that was present for
* the call to wrapCallback. */
static wrapCallback<T extends Function>(fn: T, context?: CorrelationContext): T;
/**
* Enables the CorrelationContextManager.
*/
static enable(forceClsHooked?: boolean): void;
static startOperation(context: azureFunctionsTypes.Context | (http.IncomingMessage | azureFunctionsTypes.HttpRequest) | ISpanContext, request?: azureFunctionsTypes.HttpRequest | string): CorrelationContext | null;
/**
* Disables the CorrelationContextManager.
*/
static disable(): void;
/**
* Reset the namespace
*/
static reset(): void;
/**
* Reports if CorrelationContextManager is able to run in this environment
*/
static isNodeVersionCompatible(): boolean;
/**
* We only want to use cls-hooked when it uses async_hooks api (8.2+), else
* use async-listener (plain -cls)
*/
static shouldUseClsHooked(): boolean;
/**
* A TypeError is triggered by cls-hooked for node [8.0, 8.2)
* @internal Used in tests only
*/
static canUseClsHooked(): boolean;
}
@@ -0,0 +1,249 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Logging = require("../Library/Logging");
var DiagChannel = require("./diagnostic-channel/initialization");
var Traceparent = require("../Library/Traceparent");
var Tracestate = require("../Library/Tracestate");
var HttpRequestParser = require("./HttpRequestParser");
var CorrelationContextManager = (function () {
function CorrelationContextManager() {
}
/**
* Provides the current Context.
* The context is the most recent one entered into for the current
* logical chain of execution, including across asynchronous calls.
*/
CorrelationContextManager.getCurrentContext = function () {
if (!CorrelationContextManager.enabled) {
return null;
}
var context = CorrelationContextManager.session.get(CorrelationContextManager.CONTEXT_NAME);
if (context === undefined) {
return null;
}
return context;
};
/**
* A helper to generate objects conforming to the CorrelationContext interface
*/
CorrelationContextManager.generateContextObject = function (operationId, parentId, operationName, correlationContextHeader, traceparent, tracestate) {
parentId = parentId || operationId;
if (this.enabled) {
return {
operation: {
name: operationName,
id: operationId,
parentId: parentId,
traceparent: traceparent,
tracestate: tracestate
},
customProperties: new CustomPropertiesImpl(correlationContextHeader)
};
}
return null;
};
CorrelationContextManager.spanToContextObject = function (spanContext, parentId, name) {
var traceContext = new Traceparent();
traceContext.traceId = spanContext.traceId;
traceContext.spanId = spanContext.spanId;
traceContext.traceFlag = spanContext.traceFlags || Traceparent.DEFAULT_TRACE_FLAG;
traceContext.parentId = parentId;
return CorrelationContextManager.generateContextObject(traceContext.traceId, traceContext.parentId, name, null, traceContext);
};
/**
* Runs a function inside a given Context.
* All logical children of the execution path that entered this Context
* will receive this Context object on calls to GetCurrentContext.
*/
CorrelationContextManager.runWithContext = function (context, fn) {
if (CorrelationContextManager.enabled) {
return CorrelationContextManager.session.bind(fn, (_a = {}, _a[CorrelationContextManager.CONTEXT_NAME] = context, _a))();
}
else {
return fn();
}
var _a;
};
/**
* Wrapper for cls-hooked bindEmitter method
*/
CorrelationContextManager.wrapEmitter = function (emitter) {
if (CorrelationContextManager.enabled) {
CorrelationContextManager.session.bindEmitter(emitter);
}
};
/**
* Patches a callback to restore the correct Context when getCurrentContext
* is run within it. This is necessary if automatic correlation fails to work
* with user-included libraries.
*
* The supplied callback will be given the same context that was present for
* the call to wrapCallback. */
CorrelationContextManager.wrapCallback = function (fn, context) {
if (CorrelationContextManager.enabled) {
return CorrelationContextManager.session.bind(fn, context ? (_a = {},
_a[CorrelationContextManager.CONTEXT_NAME] = context,
_a) : undefined);
}
return fn;
var _a;
};
/**
* Enables the CorrelationContextManager.
*/
CorrelationContextManager.enable = function (forceClsHooked) {
if (this.enabled) {
return;
}
if (!this.isNodeVersionCompatible()) {
this.enabled = false;
return;
}
if (!CorrelationContextManager.hasEverEnabled) {
this.forceClsHooked = forceClsHooked;
this.hasEverEnabled = true;
if (typeof this.cls === "undefined") {
if ((CorrelationContextManager.forceClsHooked === true) || (CorrelationContextManager.forceClsHooked === undefined && CorrelationContextManager.shouldUseClsHooked())) {
this.cls = require('cls-hooked');
}
else {
this.cls = require('continuation-local-storage');
}
}
CorrelationContextManager.session = this.cls.createNamespace("AI-CLS-Session");
DiagChannel.registerContextPreservation(function (cb) {
return CorrelationContextManager.session.bind(cb);
});
}
this.enabled = true;
};
CorrelationContextManager.startOperation = function (context, request) {
var traceContext = context && context.traceContext || null;
var spanContext = context && context.traceId
? context
: null;
var headers = context && context.headers;
if (spanContext) {
var traceparent = new Traceparent("00-" + spanContext.traceId + "-" + spanContext.spanId + "-01");
var tracestate = new Tracestate(spanContext.tracestate);
var correlationContext = CorrelationContextManager.generateContextObject(spanContext.traceId, "|" + spanContext.traceId + "." + spanContext.spanId + ".", typeof request === "string" ? request : "", undefined, traceparent, tracestate);
return correlationContext;
}
// AzFunction TraceContext available
if (traceContext) {
var traceparent = new Traceparent(traceContext.traceparent);
var tracestate = new Tracestate(traceContext.tracestate);
var parser = typeof request === "object"
? new HttpRequestParser(request)
: null;
var correlationContext = CorrelationContextManager.generateContextObject(traceparent.traceId, traceparent.parentId, typeof request === "string"
? request
: parser.getOperationName({}), parser && parser.getCorrelationContextHeader() || undefined, traceparent, tracestate);
return correlationContext;
}
// No TraceContext available, parse as http.IncomingMessage
if (headers) {
var traceparent = new Traceparent(headers.traceparent);
var tracestate = new Tracestate(headers.tracestate);
var parser = new HttpRequestParser(context);
var correlationContext = CorrelationContextManager.generateContextObject(traceparent.traceId, traceparent.parentId, parser.getOperationName({}), parser.getCorrelationContextHeader(), traceparent, tracestate);
return correlationContext;
}
Logging.warn("startOperation was called with invalid arguments", arguments);
return null;
};
/**
* Disables the CorrelationContextManager.
*/
CorrelationContextManager.disable = function () {
this.enabled = false;
};
/**
* Reset the namespace
*/
CorrelationContextManager.reset = function () {
if (CorrelationContextManager.hasEverEnabled) {
CorrelationContextManager.session = null;
CorrelationContextManager.session = this.cls.createNamespace('AI-CLS-Session');
}
};
/**
* Reports if CorrelationContextManager is able to run in this environment
*/
CorrelationContextManager.isNodeVersionCompatible = function () {
var nodeVer = process.versions.node.split(".");
return parseInt(nodeVer[0]) > 3 || (parseInt(nodeVer[0]) > 2 && parseInt(nodeVer[1]) > 2);
};
/**
* We only want to use cls-hooked when it uses async_hooks api (8.2+), else
* use async-listener (plain -cls)
*/
CorrelationContextManager.shouldUseClsHooked = function () {
var nodeVer = process.versions.node.split(".");
return (parseInt(nodeVer[0]) > 8) || (parseInt(nodeVer[0]) >= 8 && parseInt(nodeVer[1]) >= 2);
};
/**
* A TypeError is triggered by cls-hooked for node [8.0, 8.2)
* @internal Used in tests only
*/
CorrelationContextManager.canUseClsHooked = function () {
var nodeVer = process.versions.node.split(".");
var greater800 = (parseInt(nodeVer[0]) > 8) || (parseInt(nodeVer[0]) >= 8 && parseInt(nodeVer[1]) >= 0);
var less820 = (parseInt(nodeVer[0]) < 8) || (parseInt(nodeVer[0]) <= 8 && parseInt(nodeVer[1]) < 2);
var greater470 = parseInt(nodeVer[0]) > 4 || (parseInt(nodeVer[0]) >= 4 && parseInt(nodeVer[1]) >= 7); // cls-hooked requires node 4.7+
return !(greater800 && less820) && greater470;
};
CorrelationContextManager.enabled = false;
CorrelationContextManager.hasEverEnabled = false;
CorrelationContextManager.forceClsHooked = undefined; // true: use cls-hooked, false: use cls, undefined: choose based on node version
CorrelationContextManager.CONTEXT_NAME = "ApplicationInsights-Context";
return CorrelationContextManager;
}());
exports.CorrelationContextManager = CorrelationContextManager;
var CustomPropertiesImpl = (function () {
function CustomPropertiesImpl(header) {
this.props = [];
this.addHeaderData(header);
}
CustomPropertiesImpl.prototype.addHeaderData = function (header) {
var keyvals = header ? header.split(", ") : [];
this.props = keyvals.map(function (keyval) {
var parts = keyval.split("=");
return { key: parts[0], value: parts[1] };
}).concat(this.props);
};
CustomPropertiesImpl.prototype.serializeToHeader = function () {
return this.props.map(function (keyval) {
return keyval.key + "=" + keyval.value;
}).join(", ");
};
CustomPropertiesImpl.prototype.getProperty = function (prop) {
for (var i = 0; i < this.props.length; ++i) {
var keyval = this.props[i];
if (keyval.key === prop) {
return keyval.value;
}
}
return;
};
// TODO: Strictly according to the spec, properties which are recieved from
// an incoming request should be left untouched, while we may add our own new
// properties. The logic here will need to change to track that.
CustomPropertiesImpl.prototype.setProperty = function (prop, val) {
if (CustomPropertiesImpl.bannedCharacters.test(prop) || CustomPropertiesImpl.bannedCharacters.test(val)) {
Logging.warn("Correlation context property keys and values must not contain ',' or '='. setProperty was called with key: " + prop + " and value: " + val);
return;
}
for (var i = 0; i < this.props.length; ++i) {
var keyval = this.props[i];
if (keyval.key === prop) {
keyval.value = val;
return;
}
}
this.props.push({ key: prop, value: val });
};
CustomPropertiesImpl.bannedCharacters = /[,=]/;
return CustomPropertiesImpl;
}());
//# sourceMappingURL=CorrelationContextManager.js.map
File diff suppressed because one or more lines are too long
+19
View File
@@ -0,0 +1,19 @@
import TelemetryClient = require("../Library/TelemetryClient");
declare class AutoCollectExceptions {
static INSTANCE: AutoCollectExceptions;
static UNCAUGHT_EXCEPTION_MONITOR_HANDLER_NAME: string;
static UNCAUGHT_EXCEPTION_HANDLER_NAME: string;
static UNHANDLED_REJECTION_HANDLER_NAME: string;
private static _RETHROW_EXIT_MESSAGE;
private static _FALLBACK_ERROR_MESSAGE;
private static _canUseUncaughtExceptionMonitor;
private _exceptionListenerHandle;
private _rejectionListenerHandle;
private _client;
private _isInitialized;
constructor(client: TelemetryClient);
isInitialized(): boolean;
enable(isEnabled: boolean): void;
dispose(): void;
}
export = AutoCollectExceptions;
+78
View File
@@ -0,0 +1,78 @@
"use strict";
var AutoCollectExceptions = (function () {
function AutoCollectExceptions(client) {
if (!!AutoCollectExceptions.INSTANCE) {
throw new Error("Exception tracking should be configured from the applicationInsights object");
}
AutoCollectExceptions.INSTANCE = this;
this._client = client;
// Only use for 13.7.0+
var nodeVer = process.versions.node.split(".");
AutoCollectExceptions._canUseUncaughtExceptionMonitor = parseInt(nodeVer[0]) > 13 || (parseInt(nodeVer[0]) === 13 && parseInt(nodeVer[1]) >= 7);
}
AutoCollectExceptions.prototype.isInitialized = function () {
return this._isInitialized;
};
AutoCollectExceptions.prototype.enable = function (isEnabled) {
var _this = this;
if (isEnabled) {
this._isInitialized = true;
var self = this;
if (!this._exceptionListenerHandle) {
// For scenarios like Promise.reject(), an error won't be passed to the handle. Create a placeholder
// error for these scenarios.
var handle = function (reThrow, name, error) {
if (error === void 0) { error = new Error(AutoCollectExceptions._FALLBACK_ERROR_MESSAGE); }
_this._client.trackException({ exception: error });
_this._client.flush({ isAppCrashing: true });
// only rethrow when we are the only listener
if (reThrow && name && process.listeners(name).length === 1) {
console.error(error);
process.exit(1);
}
};
if (AutoCollectExceptions._canUseUncaughtExceptionMonitor) {
// Node.js >= 13.7.0, use uncaughtExceptionMonitor. It handles both promises and exceptions
this._exceptionListenerHandle = handle.bind(this, false, undefined); // never rethrows
process.on(AutoCollectExceptions.UNCAUGHT_EXCEPTION_MONITOR_HANDLER_NAME, this._exceptionListenerHandle);
}
else {
this._exceptionListenerHandle = handle.bind(this, true, AutoCollectExceptions.UNCAUGHT_EXCEPTION_HANDLER_NAME);
this._rejectionListenerHandle = handle.bind(this, false, undefined); // never rethrows
process.on(AutoCollectExceptions.UNCAUGHT_EXCEPTION_HANDLER_NAME, this._exceptionListenerHandle);
process.on(AutoCollectExceptions.UNHANDLED_REJECTION_HANDLER_NAME, this._rejectionListenerHandle);
}
}
}
else {
if (this._exceptionListenerHandle) {
if (AutoCollectExceptions._canUseUncaughtExceptionMonitor) {
process.removeListener(AutoCollectExceptions.UNCAUGHT_EXCEPTION_MONITOR_HANDLER_NAME, this._exceptionListenerHandle);
}
else {
process.removeListener(AutoCollectExceptions.UNCAUGHT_EXCEPTION_HANDLER_NAME, this._exceptionListenerHandle);
process.removeListener(AutoCollectExceptions.UNHANDLED_REJECTION_HANDLER_NAME, this._rejectionListenerHandle);
}
this._exceptionListenerHandle = undefined;
this._rejectionListenerHandle = undefined;
delete this._exceptionListenerHandle;
delete this._rejectionListenerHandle;
}
}
};
AutoCollectExceptions.prototype.dispose = function () {
AutoCollectExceptions.INSTANCE = null;
this.enable(false);
this._isInitialized = false;
};
AutoCollectExceptions.INSTANCE = null;
AutoCollectExceptions.UNCAUGHT_EXCEPTION_MONITOR_HANDLER_NAME = "uncaughtExceptionMonitor";
AutoCollectExceptions.UNCAUGHT_EXCEPTION_HANDLER_NAME = "uncaughtException";
AutoCollectExceptions.UNHANDLED_REJECTION_HANDLER_NAME = "unhandledRejection";
AutoCollectExceptions._RETHROW_EXIT_MESSAGE = "Application Insights Rethrow Exception Handler";
AutoCollectExceptions._FALLBACK_ERROR_MESSAGE = "A promise was rejected without providing an error. Application Insights generated this error stack for you.";
AutoCollectExceptions._canUseUncaughtExceptionMonitor = false;
return AutoCollectExceptions;
}());
module.exports = AutoCollectExceptions;
//# sourceMappingURL=Exceptions.js.map
File diff suppressed because one or more lines are too long
+24
View File
@@ -0,0 +1,24 @@
import TelemetryClient = require("../Library/TelemetryClient");
import Config = require("../Library/Config");
declare class HeartBeat {
static INSTANCE: HeartBeat;
private _collectionInterval;
private _client;
private _handle;
private _isEnabled;
private _isInitialized;
private _isVM;
private _vmData;
private _azInst_vmId;
private _azInst_subscriptionId;
private _azInst_osType;
constructor(client: TelemetryClient);
enable(isEnabled: boolean, config?: Config): void;
isInitialized(): boolean;
static isEnabled(): boolean;
trackHeartBeat(config: Config, callback: () => void): void;
dispose(): void;
private _getAzureComputeMetadata(config, callback);
private _isJSON(str);
}
export = HeartBeat;
+150
View File
@@ -0,0 +1,150 @@
"use strict";
var os = require("os");
var Constants = require("../Declarations/Constants");
var Util = require("../Library/Util");
var Context = require("../Library/Context");
var AutoCollectHttpDependencies = require("../AutoCollection/HttpDependencies");
var AIMS_URI = "http://169.254.169.254/metadata/instance/compute";
var AIMS_API_VERSION = "api-version=2017-12-01";
var AIMS_FORMAT = "format=json";
var ConnectionErrorMessage = "ENETUNREACH";
var HeartBeat = (function () {
function HeartBeat(client) {
this._collectionInterval = 900000;
this._vmData = {};
this._azInst_vmId = "";
this._azInst_subscriptionId = "";
this._azInst_osType = "";
if (!HeartBeat.INSTANCE) {
HeartBeat.INSTANCE = this;
}
this._isInitialized = false;
this._client = client;
}
HeartBeat.prototype.enable = function (isEnabled, config) {
var _this = this;
this._isEnabled = isEnabled;
if (this._isEnabled && !this._isInitialized) {
this._isInitialized = true;
}
if (isEnabled) {
if (!this._handle) {
this._handle = setInterval(function () { return _this.trackHeartBeat(config, function () { }); }, this._collectionInterval);
this._handle.unref(); // Allow the app to terminate even while this loop is going on
}
}
else {
if (this._handle) {
clearInterval(this._handle);
this._handle = null;
}
}
};
HeartBeat.prototype.isInitialized = function () {
return this._isInitialized;
};
HeartBeat.isEnabled = function () {
return HeartBeat.INSTANCE && HeartBeat.INSTANCE._isEnabled;
};
HeartBeat.prototype.trackHeartBeat = function (config, callback) {
var _this = this;
var waiting = false;
var properties = {};
var sdkVersion = Context.sdkVersion; // "node" or "node-nativeperf"
properties["sdk"] = sdkVersion;
properties["osType"] = os.type();
if (process.env.WEBSITE_SITE_NAME) {
properties["appSrv_SiteName"] = process.env.WEBSITE_SITE_NAME || "";
properties["appSrv_wsStamp"] = process.env.WEBSITE_HOME_STAMPNAME || "";
properties["appSrv_wsHost"] = process.env.WEBSITE_HOSTNAME || "";
}
else if (process.env.FUNCTIONS_WORKER_RUNTIME) {
properties["azfunction_appId"] = process.env.WEBSITE_HOSTNAME;
}
else if (config) {
if (this._isVM === undefined) {
waiting = true;
this._getAzureComputeMetadata(config, function () {
if (_this._isVM && Object.keys(_this._vmData).length > 0) {
properties["azInst_vmId"] = _this._vmData["vmId"] || "";
properties["azInst_subscriptionId"] = _this._vmData["subscriptionId"] || "";
properties["azInst_osType"] = _this._vmData["osType"] || "";
_this._azInst_vmId = _this._vmData["vmId"] || "";
_this._azInst_subscriptionId = _this._vmData["subscriptionId"] || "";
_this._azInst_osType = _this._vmData["osType"] || "";
}
_this._client.trackMetric({ name: Constants.HeartBeatMetricName, value: 0, properties: properties });
callback();
});
}
else if (this._isVM) {
properties["azInst_vmId"] = this._azInst_vmId;
properties["azInst_subscriptionId"] = this._azInst_subscriptionId;
properties["azInst_osType"] = this._azInst_osType;
}
}
if (!waiting) {
this._client.trackMetric({ name: Constants.HeartBeatMetricName, value: 0, properties: properties });
callback();
}
};
HeartBeat.prototype.dispose = function () {
HeartBeat.INSTANCE = null;
this.enable(false);
this._isInitialized = false;
};
HeartBeat.prototype._getAzureComputeMetadata = function (config, callback) {
var _this = this;
var metadataRequestUrl = AIMS_URI + "?" + AIMS_API_VERSION + "&" + AIMS_FORMAT;
var requestOptions = (_a = {
method: 'GET'
},
_a[AutoCollectHttpDependencies.disableCollectionRequestOption] = true,
_a.headers = {
"Metadata": "True",
},
_a);
var req = Util.makeRequest(config, metadataRequestUrl, requestOptions, function (res) {
if (res.statusCode === 200) {
// Success; VM
_this._isVM = true;
var virtualMachineData_1 = "";
res.on('data', function (data) {
virtualMachineData_1 += data;
});
res.on('end', function () {
_this._vmData = _this._isJSON(virtualMachineData_1) ? JSON.parse(virtualMachineData_1) : {};
callback();
});
}
else {
// else Retry on next heartbeat metrics call
callback();
}
});
if (req) {
req.on('error', function (error) {
// Unable to contact endpoint.
// Do nothing for now.
if (error && error.message && error.message.indexOf(ConnectionErrorMessage) > -1) {
_this._isVM = false; // confirm it's not in VM
}
// errors other than connect ENETUNREACH - retry
callback();
});
req.end();
}
var _a;
};
HeartBeat.prototype._isJSON = function (str) {
try {
return (JSON.parse(str) && !!str);
}
catch (e) {
return false;
}
};
return HeartBeat;
}());
module.exports = HeartBeat;
//# sourceMappingURL=HeartBeat.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,22 @@
import Contracts = require("../Declarations/Contracts");
import TelemetryClient = require("../Library/TelemetryClient");
declare class AutoCollectHttpDependencies {
static disableCollectionRequestOption: string;
static INSTANCE: AutoCollectHttpDependencies;
private static requestNumber;
private static alreadyAutoCollectedFlag;
private _client;
private _isEnabled;
private _isInitialized;
constructor(client: TelemetryClient);
enable(isEnabled: boolean): void;
isInitialized(): boolean;
private _initialize();
/**
* Tracks an outgoing request. Because it may set headers this method must be called before
* writing content to or ending the request.
*/
static trackRequest(client: TelemetryClient, telemetry: Contracts.NodeHttpDependencyTelemetry): void;
dispose(): void;
}
export = AutoCollectHttpDependencies;
+209
View File
@@ -0,0 +1,209 @@
"use strict";
var http = require("http");
var https = require("https");
var Logging = require("../Library/Logging");
var Util = require("../Library/Util");
var RequestResponseHeaders = require("../Library/RequestResponseHeaders");
var HttpDependencyParser = require("./HttpDependencyParser");
var CorrelationContextManager_1 = require("./CorrelationContextManager");
var CorrelationIdManager = require("../Library/CorrelationIdManager");
var Traceparent = require("../Library/Traceparent");
var DiagChannel = require("./diagnostic-channel/initialization");
var AutoCollectHttpDependencies = (function () {
function AutoCollectHttpDependencies(client) {
if (!!AutoCollectHttpDependencies.INSTANCE) {
throw new Error("Client request tracking should be configured from the applicationInsights object");
}
AutoCollectHttpDependencies.INSTANCE = this;
this._client = client;
}
AutoCollectHttpDependencies.prototype.enable = function (isEnabled) {
this._isEnabled = isEnabled;
if (this._isEnabled && !this._isInitialized) {
this._initialize();
}
if (DiagChannel.IsInitialized) {
require("./diagnostic-channel/azure-coretracing.sub").enable(true, this._client);
require("./diagnostic-channel/mongodb.sub").enable(isEnabled, this._client);
require("./diagnostic-channel/mysql.sub").enable(isEnabled, this._client);
require("./diagnostic-channel/redis.sub").enable(isEnabled, this._client);
require("./diagnostic-channel/postgres.sub").enable(isEnabled, this._client);
}
};
AutoCollectHttpDependencies.prototype.isInitialized = function () {
return this._isInitialized;
};
AutoCollectHttpDependencies.prototype._initialize = function () {
var _this = this;
this._isInitialized = true;
var originalGet = http.get;
var originalRequest = http.request;
var originalHttpsRequest = https.request;
var clientRequestPatch = function (request, options) {
var shouldCollect = !options[AutoCollectHttpDependencies.disableCollectionRequestOption] &&
!request[AutoCollectHttpDependencies.alreadyAutoCollectedFlag];
// If someone else patched traceparent headers onto this request
if (options.headers && options.headers['user-agent'] && options.headers['user-agent'].toString().indexOf('azsdk-js') !== -1) {
shouldCollect = false;
}
request[AutoCollectHttpDependencies.alreadyAutoCollectedFlag] = true;
if (request && options && shouldCollect) {
CorrelationContextManager_1.CorrelationContextManager.wrapEmitter(request);
AutoCollectHttpDependencies.trackRequest(_this._client, { options: options, request: request });
}
};
// On node >= v0.11.12 and < 9.0 (excluding 8.9.0) https.request just calls http.request (with additional options).
// On node < 0.11.12, 8.9.0, and 9.0 > https.request is handled separately
// Patch both and leave a flag to not double-count on versions that just call through
// We add the flag to both http and https to protect against strange double collection in other scenarios
http.request = function (options) {
var requestArgs = [];
for (var _i = 1; _i < arguments.length; _i++) {
requestArgs[_i - 1] = arguments[_i];
}
var request = originalRequest.call.apply(originalRequest, [http, options].concat(requestArgs));
clientRequestPatch(request, options);
return request;
};
https.request = function (options) {
var requestArgs = [];
for (var _i = 1; _i < arguments.length; _i++) {
requestArgs[_i - 1] = arguments[_i];
}
var request = originalHttpsRequest.call.apply(originalHttpsRequest, [https, options].concat(requestArgs));
clientRequestPatch(request, options);
return request;
};
// Node 8 calls http.request from http.get using a local reference!
// We have to patch .get manually in this case and can't just assume request is enough
// We have to replace the entire method in this case. We can't call the original.
// This is because calling the original will give us no chance to set headers as it internally does .end().
http.get = function (options) {
var requestArgs = [];
for (var _i = 1; _i < arguments.length; _i++) {
requestArgs[_i - 1] = arguments[_i];
}
var request = (_a = http.request).call.apply(_a, [http, options].concat(requestArgs));
request.end();
return request;
var _a;
};
https.get = function (options) {
var requestArgs = [];
for (var _i = 1; _i < arguments.length; _i++) {
requestArgs[_i - 1] = arguments[_i];
}
var request = (_a = https.request).call.apply(_a, [https, options].concat(requestArgs));
request.end();
return request;
var _a;
};
};
/**
* Tracks an outgoing request. Because it may set headers this method must be called before
* writing content to or ending the request.
*/
AutoCollectHttpDependencies.trackRequest = function (client, telemetry) {
if (!telemetry.options || !telemetry.request || !client) {
Logging.info("AutoCollectHttpDependencies.trackRequest was called with invalid parameters: ", !telemetry.options, !telemetry.request, !client);
return;
}
var requestParser = new HttpDependencyParser(telemetry.options, telemetry.request);
var currentContext = CorrelationContextManager_1.CorrelationContextManager.getCurrentContext();
var uniqueRequestId;
var uniqueTraceparent;
if (currentContext && currentContext.operation && currentContext.operation.traceparent && Traceparent.isValidTraceId(currentContext.operation.traceparent.traceId)) {
currentContext.operation.traceparent.updateSpanId();
uniqueRequestId = currentContext.operation.traceparent.getBackCompatRequestId();
}
else if (CorrelationIdManager.w3cEnabled) {
// Start an operation now so that we can include the w3c headers in the outgoing request
var traceparent = new Traceparent();
uniqueTraceparent = traceparent.toString();
uniqueRequestId = traceparent.getBackCompatRequestId();
}
else {
uniqueRequestId = currentContext && currentContext.operation && (currentContext.operation.parentId + AutoCollectHttpDependencies.requestNumber++ + '.');
}
// Add the source correlationId to the request headers, if a value was not already provided.
// The getHeader/setHeader methods aren't available on very old Node versions, and
// are not included in the v0.10 type declarations currently used. So check if the
// methods exist before invoking them.
if (Util.canIncludeCorrelationHeader(client, requestParser.getUrl()) && telemetry.request.getHeader && telemetry.request.setHeader) {
if (client.config && client.config.correlationId) {
// getHeader returns "any" type in newer versions of node. In basic scenarios, this will be <string | string[] | number>, but could be modified to anything else via middleware
var correlationHeader = telemetry.request.getHeader(RequestResponseHeaders.requestContextHeader);
try {
Util.safeIncludeCorrelationHeader(client, telemetry.request, correlationHeader);
}
catch (err) {
Logging.warn("Request-Context header could not be set. Correlation of requests may be lost", err);
}
if (currentContext && currentContext.operation) {
try {
telemetry.request.setHeader(RequestResponseHeaders.requestIdHeader, uniqueRequestId);
// Also set legacy headers
if (!client.config.ignoreLegacyHeaders) {
telemetry.request.setHeader(RequestResponseHeaders.parentIdHeader, currentContext.operation.id);
telemetry.request.setHeader(RequestResponseHeaders.rootIdHeader, uniqueRequestId);
}
// Set W3C headers, if available
if (uniqueTraceparent || currentContext.operation.traceparent) {
telemetry.request.setHeader(RequestResponseHeaders.traceparentHeader, uniqueTraceparent || currentContext.operation.traceparent.toString());
}
else if (CorrelationIdManager.w3cEnabled) {
// should never get here since we set uniqueTraceparent above for the w3cEnabled scenario
var traceparent = new Traceparent().toString();
telemetry.request.setHeader(RequestResponseHeaders.traceparentHeader, traceparent);
}
if (currentContext.operation.tracestate) {
var tracestate = currentContext.operation.tracestate.toString();
if (tracestate) {
telemetry.request.setHeader(RequestResponseHeaders.traceStateHeader, tracestate);
}
}
var correlationContextHeader = currentContext.customProperties.serializeToHeader();
if (correlationContextHeader) {
telemetry.request.setHeader(RequestResponseHeaders.correlationContextHeader, correlationContextHeader);
}
}
catch (err) {
Logging.warn("Correlation headers could not be set. Correlation of requests may be lost.", err);
}
}
}
}
// Collect dependency telemetry about the request when it finishes.
if (telemetry.request.on) {
telemetry.request.on('response', function (response) {
requestParser.onResponse(response);
var dependencyTelemetry = requestParser.getDependencyTelemetry(telemetry, uniqueRequestId);
dependencyTelemetry.contextObjects = dependencyTelemetry.contextObjects || {};
dependencyTelemetry.contextObjects["http.RequestOptions"] = telemetry.options;
dependencyTelemetry.contextObjects["http.ClientRequest"] = telemetry.request;
dependencyTelemetry.contextObjects["http.ClientResponse"] = response;
client.trackDependency(dependencyTelemetry);
});
telemetry.request.on('error', function (e) {
requestParser.onError(e);
var dependencyTelemetry = requestParser.getDependencyTelemetry(telemetry, uniqueRequestId);
dependencyTelemetry.contextObjects = dependencyTelemetry.contextObjects || {};
dependencyTelemetry.contextObjects["http.RequestOptions"] = telemetry.options;
dependencyTelemetry.contextObjects["http.ClientRequest"] = telemetry.request;
dependencyTelemetry.contextObjects["Error"] = e;
client.trackDependency(dependencyTelemetry);
});
}
};
AutoCollectHttpDependencies.prototype.dispose = function () {
AutoCollectHttpDependencies.INSTANCE = null;
this.enable(false);
this._isInitialized = false;
};
AutoCollectHttpDependencies.disableCollectionRequestOption = 'disableAppInsightsAutoCollection';
AutoCollectHttpDependencies.requestNumber = 1;
AutoCollectHttpDependencies.alreadyAutoCollectedFlag = '_appInsightsAutoCollected';
return AutoCollectHttpDependencies;
}());
module.exports = AutoCollectHttpDependencies;
//# sourceMappingURL=HttpDependencies.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,30 @@
/// <reference types="node" />
import http = require("http");
import https = require("https");
import Contracts = require("../Declarations/Contracts");
import RequestParser = require("./RequestParser");
/**
* Helper class to read data from the request/response objects and convert them into the telemetry contract
*/
declare class HttpDependencyParser extends RequestParser {
private correlationId;
constructor(requestOptions: object | string | http.RequestOptions | https.RequestOptions, request: http.ClientRequest);
/**
* Called when the ClientRequest emits an error event.
*/
onError(error: Error): void;
/**
* Called when the ClientRequest emits a response event.
*/
onResponse(response: http.ClientResponse): void;
/**
* Gets a dependency data contract object for a completed ClientRequest.
*/
getDependencyTelemetry(baseTelemetry?: Contracts.Telemetry, dependencyId?: string): Contracts.DependencyTelemetry;
/**
* Builds a URL from request options, using the same logic as http.request(). This is
* necessary because a ClientRequest object does not expose a url property.
*/
private static _getUrlFromRequestOptions(options, request);
}
export = HttpDependencyParser;
@@ -0,0 +1,167 @@
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var url = require("url");
var Contracts = require("../Declarations/Contracts");
var Util = require("../Library/Util");
var RequestResponseHeaders = require("../Library/RequestResponseHeaders");
var RequestParser = require("./RequestParser");
var CorrelationIdManager = require("../Library/CorrelationIdManager");
/**
* Helper class to read data from the request/response objects and convert them into the telemetry contract
*/
var HttpDependencyParser = (function (_super) {
__extends(HttpDependencyParser, _super);
function HttpDependencyParser(requestOptions, request) {
var _this = _super.call(this) || this;
if (request && request.method && requestOptions) {
// The ClientRequest.method property isn't documented, but is always there.
_this.method = request.method;
_this.url = HttpDependencyParser._getUrlFromRequestOptions(requestOptions, request);
_this.startTime = +new Date();
}
return _this;
}
/**
* Called when the ClientRequest emits an error event.
*/
HttpDependencyParser.prototype.onError = function (error) {
this._setStatus(undefined, error);
};
/**
* Called when the ClientRequest emits a response event.
*/
HttpDependencyParser.prototype.onResponse = function (response) {
this._setStatus(response.statusCode, undefined);
this.correlationId = Util.getCorrelationContextTarget(response, RequestResponseHeaders.requestContextTargetKey);
};
/**
* Gets a dependency data contract object for a completed ClientRequest.
*/
HttpDependencyParser.prototype.getDependencyTelemetry = function (baseTelemetry, dependencyId) {
var urlObject = url.parse(this.url);
urlObject.search = undefined;
urlObject.hash = undefined;
var dependencyName = this.method.toUpperCase() + " " + urlObject.pathname;
var remoteDependencyType = Contracts.RemoteDependencyDataConstants.TYPE_HTTP;
var remoteDependencyTarget = urlObject.hostname;
if (urlObject.port) {
remoteDependencyTarget += ":" + urlObject.port;
}
if (this.correlationId) {
remoteDependencyType = Contracts.RemoteDependencyDataConstants.TYPE_AI;
if (this.correlationId !== CorrelationIdManager.correlationIdPrefix) {
remoteDependencyTarget += " | " + this.correlationId;
}
}
else {
remoteDependencyType = Contracts.RemoteDependencyDataConstants.TYPE_HTTP;
}
var dependencyTelemetry = {
id: dependencyId,
name: dependencyName,
data: this.url,
duration: this.duration,
success: this._isSuccess(),
resultCode: this.statusCode ? this.statusCode.toString() : null,
properties: this.properties || {},
dependencyTypeName: remoteDependencyType,
target: remoteDependencyTarget
};
if (baseTelemetry && baseTelemetry.time) {
dependencyTelemetry.time = baseTelemetry.time;
}
else if (this.startTime) {
dependencyTelemetry.time = new Date(this.startTime);
}
// We should keep any parameters the user passed in
// Except the fields defined above in requestTelemetry, which take priority
// Except the properties field, where they're merged instead, with baseTelemetry taking priority
if (baseTelemetry) {
// Copy missing fields
for (var key in baseTelemetry) {
if (!dependencyTelemetry[key]) {
dependencyTelemetry[key] = baseTelemetry[key];
}
}
// Merge properties
if (baseTelemetry.properties) {
for (var key in baseTelemetry.properties) {
dependencyTelemetry.properties[key] = baseTelemetry.properties[key];
}
}
}
return dependencyTelemetry;
};
/**
* Builds a URL from request options, using the same logic as http.request(). This is
* necessary because a ClientRequest object does not expose a url property.
*/
HttpDependencyParser._getUrlFromRequestOptions = function (options, request) {
if (typeof options === 'string') {
if (options.indexOf("http://") === 0 || options.indexOf("https://") === 0) {
// protocol exists, parse normally
options = url.parse(options);
}
else {
// protocol not found, insert http/https where appropriate
var parsed = url.parse(options);
if (parsed.host === "443") {
options = url.parse("https://" + options);
}
else {
options = url.parse("http://" + options);
}
}
}
else if (options && typeof url.URL === 'function' && options instanceof url.URL) {
return url.format(options);
}
else {
// Avoid modifying the original options object.
var originalOptions_1 = options;
options = {};
if (originalOptions_1) {
Object.keys(originalOptions_1).forEach(function (key) {
options[key] = originalOptions_1[key];
});
}
}
// Oddly, url.format ignores path and only uses pathname and search,
// so create them from the path, if path was specified
if (options.path) {
var parsedQuery = url.parse(options.path);
options.pathname = parsedQuery.pathname;
options.search = parsedQuery.search;
}
// Similarly, url.format ignores hostname and port if host is specified,
// even if host doesn't have the port, but http.request does not work
// this way. It will use the port if one is not specified in host,
// effectively treating host as hostname, but will use the port specified
// in host if it exists.
if (options.host && options.port) {
// Force a protocol so it will parse the host as the host, not path.
// It is discarded and not used, so it doesn't matter if it doesn't match
var parsedHost = url.parse("http://" + options.host);
if (!parsedHost.port && options.port) {
options.hostname = options.host;
delete options.host;
}
}
// Mix in default values used by http.request and others
options.protocol = options.protocol || (request.agent && request.agent.protocol) || (request.protocol) || undefined;
options.hostname = options.hostname || 'localhost';
return url.format(options);
};
return HttpDependencyParser;
}(RequestParser));
module.exports = HttpDependencyParser;
//# sourceMappingURL=HttpDependencyParser.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,59 @@
/// <reference types="node" />
import http = require("http");
import Contracts = require("../Declarations/Contracts");
import RequestParser = require("./RequestParser");
import Tracestate = require("../Library/Tracestate");
import Traceparent = require("../Library/Traceparent");
import { HttpRequest } from "../Library/Functions";
/**
* Helper class to read data from the request/response objects and convert them into the telemetry contract
*/
declare class HttpRequestParser extends RequestParser {
private static keys;
private rawHeaders;
private socketRemoteAddress;
private connectionRemoteAddress;
private legacySocketRemoteAddress;
private userAgent;
private sourceCorrelationId;
private parentId;
private operationId;
private requestId;
private traceparent;
private tracestate;
private legacyRootId;
private correlationContextHeader;
constructor(request: http.IncomingMessage | HttpRequest, requestId?: string);
onError(error: Error | string, ellapsedMilliseconds?: number): void;
onResponse(response: http.ServerResponse, ellapsedMilliseconds?: number): void;
getRequestTelemetry(baseTelemetry?: Contracts.Telemetry): Contracts.RequestTelemetry;
getRequestTags(tags: {
[key: string]: string;
}): {
[key: string]: string;
};
getOperationId(tags: {
[key: string]: string;
}): string;
getOperationParentId(tags: {
[key: string]: string;
}): string;
getOperationName(tags: {
[key: string]: string;
}): string;
getRequestId(): string;
getCorrelationContextHeader(): string;
getTraceparent(): Traceparent;
getTracestate(): Tracestate;
getLegacyRootId(): string;
private _getAbsoluteUrl(request);
private _getIp();
private _getId(name);
/**
* Sets this operation's operationId, parentId, requestId (and legacyRootId, if necessary) based on this operation's traceparent
*/
private setBackCompatFromThisTraceContext();
private parseHeaders(request, requestId?);
static parseId(cookieValue: string): string;
}
export = HttpRequestParser;
@@ -0,0 +1,259 @@
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var url = require("url");
var Contracts = require("../Declarations/Contracts");
var Util = require("../Library/Util");
var RequestResponseHeaders = require("../Library/RequestResponseHeaders");
var RequestParser = require("./RequestParser");
var CorrelationIdManager = require("../Library/CorrelationIdManager");
var Tracestate = require("../Library/Tracestate");
var Traceparent = require("../Library/Traceparent");
/**
* Helper class to read data from the request/response objects and convert them into the telemetry contract
*/
var HttpRequestParser = (function (_super) {
__extends(HttpRequestParser, _super);
function HttpRequestParser(request, requestId) {
var _this = _super.call(this) || this;
if (request) {
_this.method = request.method;
_this.url = _this._getAbsoluteUrl(request);
_this.startTime = +new Date();
_this.socketRemoteAddress = request.socket && request.socket.remoteAddress;
_this.parseHeaders(request, requestId);
if (request.connection) {
_this.connectionRemoteAddress = request.connection.remoteAddress;
_this.legacySocketRemoteAddress = request.connection["socket"] && request.connection["socket"].remoteAddress;
}
}
return _this;
}
HttpRequestParser.prototype.onError = function (error, ellapsedMilliseconds) {
this._setStatus(undefined, error);
// This parameter is only for overrides. setStatus handles this internally for the autocollected case
if (ellapsedMilliseconds) {
this.duration = ellapsedMilliseconds;
}
};
HttpRequestParser.prototype.onResponse = function (response, ellapsedMilliseconds) {
this._setStatus(response.statusCode, undefined);
// This parameter is only for overrides. setStatus handles this internally for the autocollected case
if (ellapsedMilliseconds) {
this.duration = ellapsedMilliseconds;
}
};
HttpRequestParser.prototype.getRequestTelemetry = function (baseTelemetry) {
var requestTelemetry = {
id: this.requestId,
name: this.method + " " + url.parse(this.url).pathname,
url: this.url,
/*
See https://github.com/microsoft/ApplicationInsights-dotnet-server/blob/25d695e6a906fbe977f67be3966d25dbf1c50a79/Src/Web/Web.Shared.Net/RequestTrackingTelemetryModule.cs#L250
for reference
*/
source: this.sourceCorrelationId,
duration: this.duration,
resultCode: this.statusCode ? this.statusCode.toString() : null,
success: this._isSuccess(),
properties: this.properties
};
if (baseTelemetry && baseTelemetry.time) {
requestTelemetry.time = baseTelemetry.time;
}
else if (this.startTime) {
requestTelemetry.time = new Date(this.startTime);
}
// We should keep any parameters the user passed in
// Except the fields defined above in requestTelemetry, which take priority
// Except the properties field, where they're merged instead, with baseTelemetry taking priority
if (baseTelemetry) {
// Copy missing fields
for (var key in baseTelemetry) {
if (!requestTelemetry[key]) {
requestTelemetry[key] = baseTelemetry[key];
}
}
// Merge properties
if (baseTelemetry.properties) {
for (var key in baseTelemetry.properties) {
requestTelemetry.properties[key] = baseTelemetry.properties[key];
}
}
}
return requestTelemetry;
};
HttpRequestParser.prototype.getRequestTags = function (tags) {
// create a copy of the context for requests since client info will be used here
var newTags = {};
for (var key in tags) {
newTags[key] = tags[key];
}
// don't override tags if they are already set
newTags[HttpRequestParser.keys.locationIp] = tags[HttpRequestParser.keys.locationIp] || this._getIp();
newTags[HttpRequestParser.keys.sessionId] = tags[HttpRequestParser.keys.sessionId] || this._getId("ai_session");
newTags[HttpRequestParser.keys.userId] = tags[HttpRequestParser.keys.userId] || this._getId("ai_user");
newTags[HttpRequestParser.keys.userAuthUserId] = tags[HttpRequestParser.keys.userAuthUserId] || this._getId("ai_authUser");
newTags[HttpRequestParser.keys.operationName] = this.getOperationName(tags);
newTags[HttpRequestParser.keys.operationParentId] = this.getOperationParentId(tags);
newTags[HttpRequestParser.keys.operationId] = this.getOperationId(tags);
return newTags;
};
HttpRequestParser.prototype.getOperationId = function (tags) {
return tags[HttpRequestParser.keys.operationId] || this.operationId;
};
HttpRequestParser.prototype.getOperationParentId = function (tags) {
return tags[HttpRequestParser.keys.operationParentId] || this.parentId || this.getOperationId(tags);
};
HttpRequestParser.prototype.getOperationName = function (tags) {
return tags[HttpRequestParser.keys.operationName] || this.method + " " + url.parse(this.url).pathname;
};
HttpRequestParser.prototype.getRequestId = function () {
return this.requestId;
};
HttpRequestParser.prototype.getCorrelationContextHeader = function () {
return this.correlationContextHeader;
};
HttpRequestParser.prototype.getTraceparent = function () {
return this.traceparent;
};
HttpRequestParser.prototype.getTracestate = function () {
return this.tracestate;
};
HttpRequestParser.prototype.getLegacyRootId = function () {
return this.legacyRootId;
};
HttpRequestParser.prototype._getAbsoluteUrl = function (request) {
if (!request.headers) {
return request.url;
}
var encrypted = request.connection ? request.connection.encrypted : null;
var requestUrl = url.parse(request.url);
var pathName = requestUrl.pathname;
var search = requestUrl.search;
var absoluteUrl = url.format({
protocol: encrypted ? "https" : "http",
host: request.headers.host,
pathname: pathName,
search: search
});
return absoluteUrl;
};
HttpRequestParser.prototype._getIp = function () {
// regex to match ipv4 without port
// Note: including the port would cause the payload to be rejected by the data collector
var ipMatch = /[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/;
var check = function (str) {
var results = ipMatch.exec(str);
if (results) {
return results[0];
}
};
var ip = check(this.rawHeaders["x-forwarded-for"])
|| check(this.rawHeaders["x-client-ip"])
|| check(this.rawHeaders["x-real-ip"])
|| check(this.connectionRemoteAddress)
|| check(this.socketRemoteAddress)
|| check(this.legacySocketRemoteAddress);
// node v12 returns this if the address is "localhost"
if (!ip
&& this.connectionRemoteAddress
&& this.connectionRemoteAddress.substr
&& this.connectionRemoteAddress.substr(0, 2) === "::") {
ip = "127.0.0.1";
}
return ip;
};
HttpRequestParser.prototype._getId = function (name) {
var cookie = (this.rawHeaders && this.rawHeaders["cookie"] &&
typeof this.rawHeaders["cookie"] === 'string' && this.rawHeaders["cookie"]) || "";
var value = HttpRequestParser.parseId(Util.getCookie(name, cookie));
return value;
};
/**
* Sets this operation's operationId, parentId, requestId (and legacyRootId, if necessary) based on this operation's traceparent
*/
HttpRequestParser.prototype.setBackCompatFromThisTraceContext = function () {
// Set operationId
this.operationId = this.traceparent.traceId;
if (this.traceparent.legacyRootId) {
this.legacyRootId = this.traceparent.legacyRootId;
}
// Set parentId with existing spanId
this.parentId = this.traceparent.parentId;
// Update the spanId and set the current requestId
this.traceparent.updateSpanId();
this.requestId = this.traceparent.getBackCompatRequestId();
};
HttpRequestParser.prototype.parseHeaders = function (request, requestId) {
this.rawHeaders = request.headers || request.rawHeaders;
this.userAgent = request.headers && request.headers["user-agent"];
this.sourceCorrelationId = Util.getCorrelationContextTarget(request, RequestResponseHeaders.requestContextSourceKey);
if (request.headers) {
var tracestateHeader = request.headers[RequestResponseHeaders.traceStateHeader]; // w3c header
var traceparentHeader = request.headers[RequestResponseHeaders.traceparentHeader]; // w3c header
var requestIdHeader = request.headers[RequestResponseHeaders.requestIdHeader]; // default AI header
var legacy_parentId = request.headers[RequestResponseHeaders.parentIdHeader]; // legacy AI header
var legacy_rootId = request.headers[RequestResponseHeaders.rootIdHeader]; // legacy AI header
this.correlationContextHeader = request.headers[RequestResponseHeaders.correlationContextHeader];
if (CorrelationIdManager.w3cEnabled && (traceparentHeader || tracestateHeader)) {
// Parse W3C Trace Context headers
this.traceparent = new Traceparent(traceparentHeader); // new traceparent is always created from this
this.tracestate = traceparentHeader && tracestateHeader && new Tracestate(tracestateHeader); // discard tracestate if no traceparent is present
this.setBackCompatFromThisTraceContext();
}
else if (requestIdHeader) {
// Parse AI headers
if (CorrelationIdManager.w3cEnabled) {
this.traceparent = new Traceparent(null, requestIdHeader);
this.setBackCompatFromThisTraceContext();
}
else {
this.parentId = requestIdHeader;
this.requestId = CorrelationIdManager.generateRequestId(this.parentId);
this.operationId = CorrelationIdManager.getRootId(this.requestId);
}
}
else {
// Legacy fallback
if (CorrelationIdManager.w3cEnabled) {
this.traceparent = new Traceparent();
this.traceparent.parentId = legacy_parentId;
this.traceparent.legacyRootId = legacy_rootId || legacy_parentId;
this.setBackCompatFromThisTraceContext();
}
else {
this.parentId = legacy_parentId;
this.requestId = CorrelationIdManager.generateRequestId(legacy_rootId || this.parentId);
this.correlationContextHeader = null;
this.operationId = CorrelationIdManager.getRootId(this.requestId);
}
}
if (requestId) {
// For the scenarios that don't guarantee an AI-created context,
// override the requestId with the provided one.
this.requestId = requestId;
this.operationId = CorrelationIdManager.getRootId(this.requestId);
}
}
};
HttpRequestParser.parseId = function (cookieValue) {
var cookieParts = cookieValue.split("|");
if (cookieParts.length > 0) {
return cookieParts[0];
}
return ""; // old behavior was to return "" for incorrect parsing
};
HttpRequestParser.keys = new Contracts.ContextTagKeys();
return HttpRequestParser;
}(RequestParser));
module.exports = HttpRequestParser;
//# sourceMappingURL=HttpRequestParser.js.map
File diff suppressed because one or more lines are too long
+33
View File
@@ -0,0 +1,33 @@
import Contracts = require("../Declarations/Contracts");
import TelemetryClient = require("../Library/TelemetryClient");
import HttpRequestParser = require("./HttpRequestParser");
declare class AutoCollectHttpRequests {
static INSTANCE: AutoCollectHttpRequests;
private static alreadyAutoCollectedFlag;
private _client;
private _isEnabled;
private _isInitialized;
private _isAutoCorrelating;
constructor(client: TelemetryClient);
enable(isEnabled: boolean): void;
useAutoCorrelation(isEnabled: boolean, forceClsHooked?: boolean): void;
isInitialized(): boolean;
isAutoCorrelating(): boolean;
private _generateCorrelationContext(requestParser);
private _initialize();
/**
* Tracks a request synchronously (doesn't wait for response 'finish' event)
*/
static trackRequestSync(client: TelemetryClient, telemetry: Contracts.NodeHttpRequestTelemetry): void;
/**
* Tracks a request by listening to the response 'finish' event
*/
static trackRequest(client: TelemetryClient, telemetry: Contracts.NodeHttpRequestTelemetry, _requestParser?: HttpRequestParser): void;
/**
* Add the target correlationId to the response headers, if not already provided.
*/
private static addResponseCorrelationIdHeader(client, response);
private static endRequest(client, requestParser, telemetry, ellapsedMilliseconds?, error?);
dispose(): void;
}
export = AutoCollectHttpRequests;
+238
View File
@@ -0,0 +1,238 @@
"use strict";
var http = require("http");
var https = require("https");
var Logging = require("../Library/Logging");
var Util = require("../Library/Util");
var RequestResponseHeaders = require("../Library/RequestResponseHeaders");
var HttpRequestParser = require("./HttpRequestParser");
var CorrelationContextManager_1 = require("./CorrelationContextManager");
var AutoCollectPerformance = require("./Performance");
var AutoCollectHttpRequests = (function () {
function AutoCollectHttpRequests(client) {
if (!!AutoCollectHttpRequests.INSTANCE) {
throw new Error("Server request tracking should be configured from the applicationInsights object");
}
AutoCollectHttpRequests.INSTANCE = this;
this._client = client;
}
AutoCollectHttpRequests.prototype.enable = function (isEnabled) {
this._isEnabled = isEnabled;
// Autocorrelation requires automatic monitoring of incoming server requests
// Disabling autocollection but enabling autocorrelation will still enable
// request monitoring but will not produce request events
if ((this._isAutoCorrelating || this._isEnabled || AutoCollectPerformance.isEnabled()) && !this._isInitialized) {
this.useAutoCorrelation(this._isAutoCorrelating);
this._initialize();
}
};
AutoCollectHttpRequests.prototype.useAutoCorrelation = function (isEnabled, forceClsHooked) {
if (isEnabled && !this._isAutoCorrelating) {
CorrelationContextManager_1.CorrelationContextManager.enable(forceClsHooked);
}
else if (!isEnabled && this._isAutoCorrelating) {
CorrelationContextManager_1.CorrelationContextManager.disable();
}
this._isAutoCorrelating = isEnabled;
};
AutoCollectHttpRequests.prototype.isInitialized = function () {
return this._isInitialized;
};
AutoCollectHttpRequests.prototype.isAutoCorrelating = function () {
return this._isAutoCorrelating;
};
AutoCollectHttpRequests.prototype._generateCorrelationContext = function (requestParser) {
if (!this._isAutoCorrelating) {
return;
}
return CorrelationContextManager_1.CorrelationContextManager.generateContextObject(requestParser.getOperationId(this._client.context.tags), requestParser.getRequestId(), requestParser.getOperationName(this._client.context.tags), requestParser.getCorrelationContextHeader(), requestParser.getTraceparent(), requestParser.getTracestate());
};
AutoCollectHttpRequests.prototype._initialize = function () {
var _this = this;
this._isInitialized = true;
var wrapOnRequestHandler = function (onRequest) {
if (!onRequest) {
return undefined;
}
if (typeof onRequest !== 'function') {
throw new Error('onRequest handler must be a function');
}
return function (request, response) {
CorrelationContextManager_1.CorrelationContextManager.wrapEmitter(request);
CorrelationContextManager_1.CorrelationContextManager.wrapEmitter(response);
var shouldCollect = request && !request[AutoCollectHttpRequests.alreadyAutoCollectedFlag];
if (request && shouldCollect) {
// Set up correlation context
var requestParser_1 = new HttpRequestParser(request);
var correlationContext = _this._generateCorrelationContext(requestParser_1);
// Note: Check for if correlation is enabled happens within this method.
// If not enabled, function will directly call the callback.
CorrelationContextManager_1.CorrelationContextManager.runWithContext(correlationContext, function () {
if (_this._isEnabled) {
// Mark as auto collected
request[AutoCollectHttpRequests.alreadyAutoCollectedFlag] = true;
// Auto collect request
AutoCollectHttpRequests.trackRequest(_this._client, { request: request, response: response }, requestParser_1);
}
if (typeof onRequest === "function") {
onRequest(request, response);
}
});
}
else {
if (typeof onRequest === "function") {
onRequest(request, response);
}
}
};
};
// The `http.createServer` function will instantiate a new http.Server object.
// Inside the Server's constructor, it is using addListener to register the
// onRequest handler. So there are two ways to inject the wrapped onRequest handler:
// 1) Overwrite Server.prototype.addListener (and .on()) globally and not patching
// the http.createServer call. Or
// 2) Overwrite the http.createServer method and add a patched addListener to the
// fresh server instance. This seems more stable for possible future changes as
// it also covers the case where the Server might not use addListener to manage
// the callback internally.
// And also as long as the constructor uses addListener to add the handle, it is
// ok to patch the addListener after construction only. Because if we would patch
// the prototype one and the createServer method, we would wrap the handler twice
// in case of the constructor call.
var wrapServerEventHandler = function (server) {
var originalAddListener = server.addListener.bind(server);
server.addListener = function (eventType, eventHandler) {
switch (eventType) {
case 'request':
case 'checkContinue':
return originalAddListener(eventType, wrapOnRequestHandler(eventHandler));
default:
return originalAddListener(eventType, eventHandler);
}
};
// on is an alias to addListener only
server.on = server.addListener;
};
var originalHttpServer = http.createServer;
// options parameter was added in Node.js v9.6.0, v8.12.0
// function createServer(requestListener?: RequestListener): Server;
// function createServer(options: ServerOptions, requestListener?: RequestListener): Server;
http.createServer = function (param1, param2) {
// todo: get a pointer to the server so the IP address can be read from server.address
if (param2 && typeof param2 === 'function') {
var server = originalHttpServer(param1, wrapOnRequestHandler(param2));
wrapServerEventHandler(server);
return server;
}
else {
var server = originalHttpServer(wrapOnRequestHandler(param1));
wrapServerEventHandler(server);
return server;
}
};
var originalHttpsServer = https.createServer;
https.createServer = function (options, onRequest) {
var server = originalHttpsServer(options, wrapOnRequestHandler(onRequest));
wrapServerEventHandler(server);
return server;
};
};
/**
* Tracks a request synchronously (doesn't wait for response 'finish' event)
*/
AutoCollectHttpRequests.trackRequestSync = function (client, telemetry) {
if (!telemetry.request || !telemetry.response || !client) {
Logging.info("AutoCollectHttpRequests.trackRequestSync was called with invalid parameters: ", !telemetry.request, !telemetry.response, !client);
return;
}
AutoCollectHttpRequests.addResponseCorrelationIdHeader(client, telemetry.response);
// store data about the request
var correlationContext = CorrelationContextManager_1.CorrelationContextManager.getCurrentContext();
var requestParser = new HttpRequestParser(telemetry.request, (correlationContext && correlationContext.operation.parentId));
// Overwrite correlation context with request parser results
if (correlationContext) {
correlationContext.operation.id = requestParser.getOperationId(client.context.tags) || correlationContext.operation.id;
correlationContext.operation.name = requestParser.getOperationName(client.context.tags) || correlationContext.operation.name;
correlationContext.operation.parentId = requestParser.getRequestId() || correlationContext.operation.parentId;
correlationContext.customProperties.addHeaderData(requestParser.getCorrelationContextHeader());
}
AutoCollectHttpRequests.endRequest(client, requestParser, telemetry, telemetry.duration, telemetry.error);
};
/**
* Tracks a request by listening to the response 'finish' event
*/
AutoCollectHttpRequests.trackRequest = function (client, telemetry, _requestParser) {
if (!telemetry.request || !telemetry.response || !client) {
Logging.info("AutoCollectHttpRequests.trackRequest was called with invalid parameters: ", !telemetry.request, !telemetry.response, !client);
return;
}
// store data about the request
var correlationContext = CorrelationContextManager_1.CorrelationContextManager.getCurrentContext();
var requestParser = _requestParser || new HttpRequestParser(telemetry.request, correlationContext && correlationContext.operation.parentId);
if (Util.canIncludeCorrelationHeader(client, requestParser.getUrl())) {
AutoCollectHttpRequests.addResponseCorrelationIdHeader(client, telemetry.response);
}
// Overwrite correlation context with request parser results (if not an automatic track. we've already precalculated the correlation context in that case)
if (correlationContext && !_requestParser) {
correlationContext.operation.id = requestParser.getOperationId(client.context.tags) || correlationContext.operation.id;
correlationContext.operation.name = requestParser.getOperationName(client.context.tags) || correlationContext.operation.name;
correlationContext.operation.parentId = requestParser.getOperationParentId(client.context.tags) || correlationContext.operation.parentId;
correlationContext.customProperties.addHeaderData(requestParser.getCorrelationContextHeader());
}
// response listeners
if (telemetry.response.once) {
telemetry.response.once("finish", function () {
AutoCollectHttpRequests.endRequest(client, requestParser, telemetry, null, null);
});
}
// track a failed request if an error is emitted
if (telemetry.request.on) {
telemetry.request.on("error", function (error) {
AutoCollectHttpRequests.endRequest(client, requestParser, telemetry, null, error);
});
}
};
/**
* Add the target correlationId to the response headers, if not already provided.
*/
AutoCollectHttpRequests.addResponseCorrelationIdHeader = function (client, response) {
if (client.config && client.config.correlationId &&
response.getHeader && response.setHeader && !response.headersSent) {
var correlationHeader = response.getHeader(RequestResponseHeaders.requestContextHeader);
Util.safeIncludeCorrelationHeader(client, response, correlationHeader);
}
};
AutoCollectHttpRequests.endRequest = function (client, requestParser, telemetry, ellapsedMilliseconds, error) {
if (error) {
requestParser.onError(error, ellapsedMilliseconds);
}
else {
requestParser.onResponse(telemetry.response, ellapsedMilliseconds);
}
var requestTelemetry = requestParser.getRequestTelemetry(telemetry);
requestTelemetry.tagOverrides = requestParser.getRequestTags(client.context.tags);
if (telemetry.tagOverrides) {
for (var key in telemetry.tagOverrides) {
requestTelemetry.tagOverrides[key] = telemetry.tagOverrides[key];
}
}
var legacyRootId = requestParser.getLegacyRootId();
if (legacyRootId) {
requestTelemetry.properties["ai_legacyRootId"] = legacyRootId;
}
requestTelemetry.contextObjects = requestTelemetry.contextObjects || {};
requestTelemetry.contextObjects["http.ServerRequest"] = telemetry.request;
requestTelemetry.contextObjects["http.ServerResponse"] = telemetry.response;
client.trackRequest(requestTelemetry);
};
AutoCollectHttpRequests.prototype.dispose = function () {
AutoCollectHttpRequests.INSTANCE = null;
this.enable(false);
this._isInitialized = false;
CorrelationContextManager_1.CorrelationContextManager.disable();
this._isAutoCorrelating = false;
};
AutoCollectHttpRequests.alreadyAutoCollectedFlag = '_appInsightsAutoCollected';
return AutoCollectHttpRequests;
}());
module.exports = AutoCollectHttpRequests;
//# sourceMappingURL=HttpRequests.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,85 @@
import TelemetryClient = require("../Library/TelemetryClient");
/**
* Interface which defines which specific extended metrics should be disabled
*
* @export
* @interface IDisabledExtendedMetrics
*/
export interface IDisabledExtendedMetrics {
gc?: boolean;
heap?: boolean;
loop?: boolean;
}
export declare class AutoCollectNativePerformance {
static INSTANCE: AutoCollectNativePerformance;
private static _emitter;
private static _metricsAvailable;
private _isEnabled;
private _isInitialized;
private _handle;
private _client;
private _disabledMetrics;
constructor(client: TelemetryClient);
/**
* Reports if NativePerformance is able to run in this environment
*/
static isNodeVersionCompatible(): boolean;
/**
* Start instance of native metrics agent.
*
* @param {boolean} isEnabled
* @param {number} [collectionInterval=60000]
* @memberof AutoCollectNativePerformance
*/
enable(isEnabled: boolean, disabledMetrics?: IDisabledExtendedMetrics, collectionInterval?: number): void;
/**
* Cleanup this instance of AutoCollectNativePerformance
*
* @memberof AutoCollectNativePerformance
*/
dispose(): void;
/**
* Parse environment variable and overwrite isEnabled based on respective fields being set
*
* @private
* @static
* @param {(boolean | IDisabledExtendedMetrics)} collectExtendedMetrics
* @returns {(boolean | IDisabledExtendedMetrics)}
* @memberof AutoCollectNativePerformance
*/
static parseEnabled(collectExtendedMetrics: boolean | IDisabledExtendedMetrics): {
isEnabled: boolean;
disabledMetrics: IDisabledExtendedMetrics;
};
/**
* Trigger an iteration of native metrics collection
*
* @private
* @memberof AutoCollectNativePerformance
*/
private _trackNativeMetrics();
/**
* Tracks garbage collection stats for this interval. One custom metric is sent per type of garbage
* collection that occurred during this collection interval.
*
* @private
* @memberof AutoCollectNativePerformance
*/
private _trackGarbageCollection();
/**
* Tracks event loop ticks per interval as a custom metric. Also included in the metric is min/max/avg
* time spent in event loop for this interval.
*
* @private
* @returns {void}
* @memberof AutoCollectNativePerformance
*/
private _trackEventLoop();
/**
* Track heap memory usage metrics as a custom metric.
*
* @private
* @memberof AutoCollectNativePerformance
*/
private _trackHeapUsage();
}
@@ -0,0 +1,251 @@
"use strict";
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
var Config = require("../Library/Config");
var Context = require("../Library/Context");
var Logging = require("../Library/Logging");
var AutoCollectNativePerformance = (function () {
function AutoCollectNativePerformance(client) {
this._disabledMetrics = {};
// Note: Only 1 instance of this can exist. So when we reconstruct this object,
// just disable old native instance and reset JS member variables
if (AutoCollectNativePerformance.INSTANCE) {
AutoCollectNativePerformance.INSTANCE.dispose();
}
AutoCollectNativePerformance.INSTANCE = this;
this._client = client;
}
/**
* Reports if NativePerformance is able to run in this environment
*/
AutoCollectNativePerformance.isNodeVersionCompatible = function () {
var nodeVer = process.versions.node.split(".");
return parseInt(nodeVer[0]) >= 6;
};
/**
* Start instance of native metrics agent.
*
* @param {boolean} isEnabled
* @param {number} [collectionInterval=60000]
* @memberof AutoCollectNativePerformance
*/
AutoCollectNativePerformance.prototype.enable = function (isEnabled, disabledMetrics, collectionInterval) {
var _this = this;
if (disabledMetrics === void 0) { disabledMetrics = {}; }
if (collectionInterval === void 0) { collectionInterval = 60000; }
if (!AutoCollectNativePerformance.isNodeVersionCompatible()) {
return;
}
if (AutoCollectNativePerformance._metricsAvailable == undefined && isEnabled && !this._isInitialized) {
// Try to require in the native-metrics library. If it's found initialize it, else do nothing and never try again.
try {
var NativeMetricsEmitters = require("applicationinsights-native-metrics");
AutoCollectNativePerformance._emitter = new NativeMetricsEmitters();
AutoCollectNativePerformance._metricsAvailable = true;
Logging.info("Native metrics module successfully loaded!");
}
catch (err) {
// Package not available. Never try again
AutoCollectNativePerformance._metricsAvailable = false;
return;
}
}
this._isEnabled = isEnabled;
this._disabledMetrics = disabledMetrics;
if (this._isEnabled && !this._isInitialized) {
this._isInitialized = true;
}
// Enable the emitter if we were able to construct one
if (this._isEnabled && AutoCollectNativePerformance._emitter) {
// enable self
AutoCollectNativePerformance._emitter.enable(true, collectionInterval);
this._handle = setInterval(function () { return _this._trackNativeMetrics(); }, collectionInterval);
this._handle.unref();
}
else if (AutoCollectNativePerformance._emitter) {
// disable self
AutoCollectNativePerformance._emitter.enable(false);
if (this._handle) {
clearInterval(this._handle);
this._handle = undefined;
}
}
};
/**
* Cleanup this instance of AutoCollectNativePerformance
*
* @memberof AutoCollectNativePerformance
*/
AutoCollectNativePerformance.prototype.dispose = function () {
this.enable(false);
};
/**
* Parse environment variable and overwrite isEnabled based on respective fields being set
*
* @private
* @static
* @param {(boolean | IDisabledExtendedMetrics)} collectExtendedMetrics
* @returns {(boolean | IDisabledExtendedMetrics)}
* @memberof AutoCollectNativePerformance
*/
AutoCollectNativePerformance.parseEnabled = function (collectExtendedMetrics) {
var disableAll = process.env[Config.ENV_nativeMetricsDisableAll];
var individualOptOuts = process.env[Config.ENV_nativeMetricsDisablers];
// case 1: disable all env var set, RETURN with isEnabled=false
if (disableAll) {
return { isEnabled: false, disabledMetrics: {} };
}
// case 2: individual env vars set, RETURN with isEnabled=true, disabledMetrics={...}
if (individualOptOuts) {
var optOutsArr = individualOptOuts.split(",");
var disabledMetrics = {};
if (optOutsArr.length > 0) {
for (var _i = 0, optOutsArr_1 = optOutsArr; _i < optOutsArr_1.length; _i++) {
var opt = optOutsArr_1[_i];
disabledMetrics[opt] = true;
}
}
// case 2a: collectExtendedMetrics is an object, overwrite existing ones if they exist
if (typeof collectExtendedMetrics === "object") {
return { isEnabled: true, disabledMetrics: __assign({}, collectExtendedMetrics, disabledMetrics) };
}
// case 2b: collectExtendedMetrics is a boolean, set disabledMetrics as is
return { isEnabled: collectExtendedMetrics, disabledMetrics: disabledMetrics };
}
// case 4: no env vars set, input arg is a boolean, RETURN with isEnabled=collectExtendedMetrics, disabledMetrics={}
if (typeof collectExtendedMetrics === "boolean") {
return { isEnabled: collectExtendedMetrics, disabledMetrics: {} };
}
else {
// case 5: no env vars set, input arg is object, RETURN with isEnabled=true, disabledMetrics=collectExtendedMetrics
return { isEnabled: true, disabledMetrics: collectExtendedMetrics };
}
};
/**
* Trigger an iteration of native metrics collection
*
* @private
* @memberof AutoCollectNativePerformance
*/
AutoCollectNativePerformance.prototype._trackNativeMetrics = function () {
var shouldSendAll = true;
if (typeof this._isEnabled !== "object") {
shouldSendAll = this._isEnabled;
}
if (shouldSendAll) {
this._trackGarbageCollection();
this._trackEventLoop();
this._trackHeapUsage();
}
};
/**
* Tracks garbage collection stats for this interval. One custom metric is sent per type of garbage
* collection that occurred during this collection interval.
*
* @private
* @memberof AutoCollectNativePerformance
*/
AutoCollectNativePerformance.prototype._trackGarbageCollection = function () {
if (this._disabledMetrics.gc) {
return;
}
var gcData = AutoCollectNativePerformance._emitter.getGCData();
for (var gc in gcData) {
var metrics = gcData[gc].metrics;
var name_1 = gc + " Garbage Collection Duration";
var stdDev = Math.sqrt(metrics.sumSquares / metrics.count - Math.pow(metrics.total / metrics.count, 2)) || 0;
this._client.trackMetric({
name: name_1,
value: metrics.total,
count: metrics.count,
max: metrics.max,
min: metrics.min,
stdDev: stdDev,
tagOverrides: (_a = {},
_a[this._client.context.keys.internalSdkVersion] = "node-nativeperf:" + Context.sdkVersion,
_a)
});
}
var _a;
};
/**
* Tracks event loop ticks per interval as a custom metric. Also included in the metric is min/max/avg
* time spent in event loop for this interval.
*
* @private
* @returns {void}
* @memberof AutoCollectNativePerformance
*/
AutoCollectNativePerformance.prototype._trackEventLoop = function () {
if (this._disabledMetrics.loop) {
return;
}
var loopData = AutoCollectNativePerformance._emitter.getLoopData();
var metrics = loopData.loopUsage;
if (metrics.count == 0) {
return;
}
var name = "Event Loop CPU Time";
var stdDev = Math.sqrt(metrics.sumSquares / metrics.count - Math.pow(metrics.total / metrics.count, 2)) || 0;
this._client.trackMetric({
name: name,
value: metrics.total,
count: metrics.count,
min: metrics.min,
max: metrics.max,
stdDev: stdDev,
tagOverrides: (_a = {},
_a[this._client.context.keys.internalSdkVersion] = "node-nativeperf:" + Context.sdkVersion,
_a)
});
var _a;
};
/**
* Track heap memory usage metrics as a custom metric.
*
* @private
* @memberof AutoCollectNativePerformance
*/
AutoCollectNativePerformance.prototype._trackHeapUsage = function () {
if (this._disabledMetrics.heap) {
return;
}
var memoryUsage = process.memoryUsage();
var heapUsed = memoryUsage.heapUsed, heapTotal = memoryUsage.heapTotal, rss = memoryUsage.rss;
this._client.trackMetric({
name: "Memory Usage (Heap)",
value: heapUsed,
count: 1,
tagOverrides: (_a = {},
_a[this._client.context.keys.internalSdkVersion] = "node-nativeperf:" + Context.sdkVersion,
_a)
});
this._client.trackMetric({
name: "Memory Total (Heap)",
value: heapTotal,
count: 1,
tagOverrides: (_b = {},
_b[this._client.context.keys.internalSdkVersion] = "node-nativeperf:" + Context.sdkVersion,
_b)
});
this._client.trackMetric({
name: "Memory Usage (Non-Heap)",
value: rss - heapTotal,
count: 1,
tagOverrides: (_c = {},
_c[this._client.context.keys.internalSdkVersion] = "node-nativeperf:" + Context.sdkVersion,
_c)
});
var _a, _b, _c;
};
return AutoCollectNativePerformance;
}());
exports.AutoCollectNativePerformance = AutoCollectNativePerformance;
//# sourceMappingURL=NativePerformance.js.map
File diff suppressed because one or more lines are too long
+45
View File
@@ -0,0 +1,45 @@
import TelemetryClient = require("../Library/TelemetryClient");
declare class AutoCollectPerformance {
static INSTANCE: AutoCollectPerformance;
private static _totalRequestCount;
private static _totalFailedRequestCount;
private static _lastRequestExecutionTime;
private static _totalDependencyCount;
private static _totalFailedDependencyCount;
private static _lastDependencyExecutionTime;
private static _totalExceptionCount;
private static _intervalDependencyExecutionTime;
private static _intervalRequestExecutionTime;
private _lastIntervalRequestExecutionTime;
private _lastIntervalDependencyExecutionTime;
private _enableLiveMetricsCounters;
private _collectionInterval;
private _client;
private _handle;
private _isEnabled;
private _isInitialized;
private _lastAppCpuUsage;
private _lastHrtime;
private _lastCpus;
private _lastDependencies;
private _lastRequests;
private _lastExceptions;
/**
* @param enableLiveMetricsCounters - enable sending additional live metrics information (dependency metrics, exception metrics, committed memory)
*/
constructor(client: TelemetryClient, collectionInterval?: number, enableLiveMetricsCounters?: boolean);
enable(isEnabled: boolean, collectionInterval?: number): void;
static countRequest(duration: number | string, success: boolean): void;
static countException(): void;
static countDependency(duration: number | string, success: boolean): void;
isInitialized(): boolean;
static isEnabled(): boolean;
trackPerformance(): void;
private _trackCpu();
private _trackMemory();
private _trackNetwork();
private _trackDependencyRate();
private _trackExceptionRate();
dispose(): void;
}
export = AutoCollectPerformance;
+278
View File
@@ -0,0 +1,278 @@
"use strict";
var os = require("os");
var Constants = require("../Declarations/Constants");
var AutoCollectPerformance = (function () {
/**
* @param enableLiveMetricsCounters - enable sending additional live metrics information (dependency metrics, exception metrics, committed memory)
*/
function AutoCollectPerformance(client, collectionInterval, enableLiveMetricsCounters) {
if (collectionInterval === void 0) { collectionInterval = 60000; }
if (enableLiveMetricsCounters === void 0) { enableLiveMetricsCounters = false; }
this._lastIntervalRequestExecutionTime = 0; // the sum of durations which took place during from app start until last interval
this._lastIntervalDependencyExecutionTime = 0;
if (!AutoCollectPerformance.INSTANCE) {
AutoCollectPerformance.INSTANCE = this;
}
this._isInitialized = false;
this._client = client;
this._collectionInterval = collectionInterval;
this._enableLiveMetricsCounters = enableLiveMetricsCounters;
}
AutoCollectPerformance.prototype.enable = function (isEnabled, collectionInterval) {
var _this = this;
this._isEnabled = isEnabled;
if (this._isEnabled && !this._isInitialized) {
this._isInitialized = true;
}
if (isEnabled) {
if (!this._handle) {
this._lastCpus = os.cpus();
this._lastRequests = {
totalRequestCount: AutoCollectPerformance._totalRequestCount,
totalFailedRequestCount: AutoCollectPerformance._totalFailedRequestCount,
time: +new Date
};
this._lastDependencies = {
totalDependencyCount: AutoCollectPerformance._totalDependencyCount,
totalFailedDependencyCount: AutoCollectPerformance._totalFailedDependencyCount,
time: +new Date
};
this._lastExceptions = {
totalExceptionCount: AutoCollectPerformance._totalExceptionCount,
time: +new Date
};
if (typeof process.cpuUsage === 'function') {
this._lastAppCpuUsage = process.cpuUsage();
}
this._lastHrtime = process.hrtime();
this._collectionInterval = collectionInterval || this._collectionInterval;
this._handle = setInterval(function () { return _this.trackPerformance(); }, this._collectionInterval);
this._handle.unref(); // Allow the app to terminate even while this loop is going on
}
}
else {
if (this._handle) {
clearInterval(this._handle);
this._handle = undefined;
}
}
};
AutoCollectPerformance.countRequest = function (duration, success) {
var durationMs;
if (!AutoCollectPerformance.isEnabled()) {
return;
}
if (typeof duration === 'string') {
// dependency duration is passed in as "00:00:00.123" by autocollectors
durationMs = +new Date('1970-01-01T' + duration + 'Z'); // convert to num ms, returns NaN if wrong
}
else if (typeof duration === 'number') {
durationMs = duration;
}
else {
return;
}
AutoCollectPerformance._intervalRequestExecutionTime += durationMs;
if (success === false) {
AutoCollectPerformance._totalFailedRequestCount++;
}
AutoCollectPerformance._totalRequestCount++;
};
AutoCollectPerformance.countException = function () {
AutoCollectPerformance._totalExceptionCount++;
};
AutoCollectPerformance.countDependency = function (duration, success) {
var durationMs;
if (!AutoCollectPerformance.isEnabled()) {
return;
}
if (typeof duration === 'string') {
// dependency duration is passed in as "00:00:00.123" by autocollectors
durationMs = +new Date('1970-01-01T' + duration + 'Z'); // convert to num ms, returns NaN if wrong
}
else if (typeof duration === 'number') {
durationMs = duration;
}
else {
return;
}
AutoCollectPerformance._intervalDependencyExecutionTime += durationMs;
if (success === false) {
AutoCollectPerformance._totalFailedDependencyCount++;
}
AutoCollectPerformance._totalDependencyCount++;
};
AutoCollectPerformance.prototype.isInitialized = function () {
return this._isInitialized;
};
AutoCollectPerformance.isEnabled = function () {
return AutoCollectPerformance.INSTANCE && AutoCollectPerformance.INSTANCE._isEnabled;
};
AutoCollectPerformance.prototype.trackPerformance = function () {
this._trackCpu();
this._trackMemory();
this._trackNetwork();
this._trackDependencyRate();
this._trackExceptionRate();
};
AutoCollectPerformance.prototype._trackCpu = function () {
// this reports total ms spent in each category since the OS was booted, to calculate percent it is necessary
// to find the delta since the last measurement
var cpus = os.cpus();
if (cpus && cpus.length && this._lastCpus && cpus.length === this._lastCpus.length) {
var totalUser = 0;
var totalSys = 0;
var totalNice = 0;
var totalIdle = 0;
var totalIrq = 0;
for (var i = 0; !!cpus && i < cpus.length; i++) {
var cpu = cpus[i];
var lastCpu = this._lastCpus[i];
var name = "% cpu(" + i + ") ";
var model = cpu.model;
var speed = cpu.speed;
var times = cpu.times;
var lastTimes = lastCpu.times;
// user cpu time (or) % CPU time spent in user space
var user = (times.user - lastTimes.user) || 0;
totalUser += user;
// system cpu time (or) % CPU time spent in kernel space
var sys = (times.sys - lastTimes.sys) || 0;
totalSys += sys;
// user nice cpu time (or) % CPU time spent on low priority processes
var nice = (times.nice - lastTimes.nice) || 0;
totalNice += nice;
// idle cpu time (or) % CPU time spent idle
var idle = (times.idle - lastTimes.idle) || 0;
totalIdle += idle;
// irq (or) % CPU time spent servicing/handling hardware interrupts
var irq = (times.irq - lastTimes.irq) || 0;
totalIrq += irq;
}
// Calculate % of total cpu time (user + system) this App Process used (Only supported by node v6.1.0+)
var appCpuPercent = undefined;
if (typeof process.cpuUsage === 'function') {
var appCpuUsage = process.cpuUsage();
var hrtime = process.hrtime();
var totalApp = ((appCpuUsage.user - this._lastAppCpuUsage.user) + (appCpuUsage.system - this._lastAppCpuUsage.system)) || 0;
if (typeof this._lastHrtime !== 'undefined' && this._lastHrtime.length === 2) {
var elapsedTime = ((hrtime[0] - this._lastHrtime[0]) * 1e6 + (hrtime[1] - this._lastHrtime[1]) / 1e3) || 0; // convert to microseconds
appCpuPercent = 100 * totalApp / (elapsedTime * cpus.length);
}
// Set previous
this._lastAppCpuUsage = appCpuUsage;
this._lastHrtime = hrtime;
}
var combinedTotal = (totalUser + totalSys + totalNice + totalIdle + totalIrq) || 1;
this._client.trackMetric({ name: Constants.PerformanceCounter.PROCESSOR_TIME, value: ((combinedTotal - totalIdle) / combinedTotal) * 100 });
this._client.trackMetric({ name: Constants.PerformanceCounter.PROCESS_TIME, value: appCpuPercent || ((totalUser / combinedTotal) * 100) });
}
this._lastCpus = cpus;
};
AutoCollectPerformance.prototype._trackMemory = function () {
var freeMem = os.freemem();
var usedMem = process.memoryUsage().rss;
var committedMemory = os.totalmem() - freeMem;
this._client.trackMetric({ name: Constants.PerformanceCounter.PRIVATE_BYTES, value: usedMem });
this._client.trackMetric({ name: Constants.PerformanceCounter.AVAILABLE_BYTES, value: freeMem });
// Only supported by quickpulse service
if (this._enableLiveMetricsCounters) {
this._client.trackMetric({ name: Constants.QuickPulseCounter.COMMITTED_BYTES, value: committedMemory });
}
};
AutoCollectPerformance.prototype._trackNetwork = function () {
// track total request counters
var lastRequests = this._lastRequests;
var requests = {
totalRequestCount: AutoCollectPerformance._totalRequestCount,
totalFailedRequestCount: AutoCollectPerformance._totalFailedRequestCount,
time: +new Date
};
var intervalRequests = (requests.totalRequestCount - lastRequests.totalRequestCount) || 0;
var intervalFailedRequests = (requests.totalFailedRequestCount - lastRequests.totalFailedRequestCount) || 0;
var elapsedMs = requests.time - lastRequests.time;
var elapsedSeconds = elapsedMs / 1000;
var averageRequestExecutionTime = ((AutoCollectPerformance._intervalRequestExecutionTime - this._lastIntervalRequestExecutionTime) / intervalRequests) || 0; // default to 0 in case no requests in this interval
this._lastIntervalRequestExecutionTime = AutoCollectPerformance._intervalRequestExecutionTime; // reset
if (elapsedMs > 0) {
var requestsPerSec = intervalRequests / elapsedSeconds;
var failedRequestsPerSec = intervalFailedRequests / elapsedSeconds;
this._client.trackMetric({ name: Constants.PerformanceCounter.REQUEST_RATE, value: requestsPerSec });
// Only send duration to live metrics if it has been updated!
if (!this._enableLiveMetricsCounters || intervalRequests > 0) {
this._client.trackMetric({ name: Constants.PerformanceCounter.REQUEST_DURATION, value: averageRequestExecutionTime });
}
// Only supported by quickpulse service
if (this._enableLiveMetricsCounters) {
this._client.trackMetric({ name: Constants.QuickPulseCounter.REQUEST_FAILURE_RATE, value: failedRequestsPerSec });
}
}
this._lastRequests = requests;
};
// Static counter is accumulated externally. Report the rate to client here
// Note: This is currently only used with QuickPulse client
AutoCollectPerformance.prototype._trackDependencyRate = function () {
if (this._enableLiveMetricsCounters) {
var lastDependencies = this._lastDependencies;
var dependencies = {
totalDependencyCount: AutoCollectPerformance._totalDependencyCount,
totalFailedDependencyCount: AutoCollectPerformance._totalFailedDependencyCount,
time: +new Date
};
var intervalDependencies = (dependencies.totalDependencyCount - lastDependencies.totalDependencyCount) || 0;
var intervalFailedDependencies = (dependencies.totalFailedDependencyCount - lastDependencies.totalFailedDependencyCount) || 0;
var elapsedMs = dependencies.time - lastDependencies.time;
var elapsedSeconds = elapsedMs / 1000;
var averageDependencyExecutionTime = ((AutoCollectPerformance._intervalDependencyExecutionTime - this._lastIntervalDependencyExecutionTime) / intervalDependencies) || 0;
this._lastIntervalDependencyExecutionTime = AutoCollectPerformance._intervalDependencyExecutionTime; // reset
if (elapsedMs > 0) {
var dependenciesPerSec = intervalDependencies / elapsedSeconds;
var failedDependenciesPerSec = intervalFailedDependencies / elapsedSeconds;
this._client.trackMetric({ name: Constants.QuickPulseCounter.DEPENDENCY_RATE, value: dependenciesPerSec });
this._client.trackMetric({ name: Constants.QuickPulseCounter.DEPENDENCY_FAILURE_RATE, value: failedDependenciesPerSec });
// redundant check for livemetrics, but kept for consistency w/ requests
// Only send duration to live metrics if it has been updated!
if (!this._enableLiveMetricsCounters || intervalDependencies > 0) {
this._client.trackMetric({ name: Constants.QuickPulseCounter.DEPENDENCY_DURATION, value: averageDependencyExecutionTime });
}
}
this._lastDependencies = dependencies;
}
};
// Static counter is accumulated externally. Report the rate to client here
// Note: This is currently only used with QuickPulse client
AutoCollectPerformance.prototype._trackExceptionRate = function () {
if (this._enableLiveMetricsCounters) {
var lastExceptions = this._lastExceptions;
var exceptions = {
totalExceptionCount: AutoCollectPerformance._totalExceptionCount,
time: +new Date
};
var intervalExceptions = (exceptions.totalExceptionCount - lastExceptions.totalExceptionCount) || 0;
var elapsedMs = exceptions.time - lastExceptions.time;
var elapsedSeconds = elapsedMs / 1000;
if (elapsedMs > 0) {
var exceptionsPerSec = intervalExceptions / elapsedSeconds;
this._client.trackMetric({ name: Constants.QuickPulseCounter.EXCEPTION_RATE, value: exceptionsPerSec });
}
this._lastExceptions = exceptions;
}
};
AutoCollectPerformance.prototype.dispose = function () {
AutoCollectPerformance.INSTANCE = null;
this.enable(false);
this._isInitialized = false;
};
AutoCollectPerformance._totalRequestCount = 0;
AutoCollectPerformance._totalFailedRequestCount = 0;
AutoCollectPerformance._lastRequestExecutionTime = 0;
AutoCollectPerformance._totalDependencyCount = 0;
AutoCollectPerformance._totalFailedDependencyCount = 0;
AutoCollectPerformance._lastDependencyExecutionTime = 0;
AutoCollectPerformance._totalExceptionCount = 0;
AutoCollectPerformance._intervalDependencyExecutionTime = 0;
AutoCollectPerformance._intervalRequestExecutionTime = 0;
return AutoCollectPerformance;
}());
module.exports = AutoCollectPerformance;
//# sourceMappingURL=Performance.js.map
File diff suppressed because one or more lines are too long
+22
View File
@@ -0,0 +1,22 @@
/**
* Base class for helpers that read data from HTTP request/response objects and convert them
* into the telemetry contract objects.
*/
declare abstract class RequestParser {
protected method: string;
protected url: string;
protected startTime: number;
protected duration: number;
protected statusCode: number;
protected properties: {
[key: string]: string;
};
/**
* Gets a url parsed out from request options
*/
getUrl(): string;
protected RequestParser(): void;
protected _setStatus(status: number, error: Error | string): void;
protected _isSuccess(): boolean;
}
export = RequestParser;
+44
View File
@@ -0,0 +1,44 @@
"use strict";
/**
* Base class for helpers that read data from HTTP request/response objects and convert them
* into the telemetry contract objects.
*/
var RequestParser = (function () {
function RequestParser() {
}
/**
* Gets a url parsed out from request options
*/
RequestParser.prototype.getUrl = function () {
return this.url;
};
RequestParser.prototype.RequestParser = function () {
this.startTime = +new Date();
};
RequestParser.prototype._setStatus = function (status, error) {
var endTime = +new Date();
this.duration = endTime - this.startTime;
this.statusCode = status;
var properties = this.properties || {};
if (error) {
if (typeof error === "string") {
properties["error"] = error;
}
else if (error instanceof Error) {
properties["error"] = error.message;
}
else if (typeof error === "object") {
for (var key in error) {
properties[key] = error[key] && error[key].toString && error[key].toString();
}
}
}
this.properties = properties;
};
RequestParser.prototype._isSuccess = function () {
return (0 < this.statusCode) && (this.statusCode < 400);
};
return RequestParser;
}());
module.exports = RequestParser;
//# sourceMappingURL=RequestParser.js.map
@@ -0,0 +1 @@
{"version":3,"file":"RequestParser.js","sourceRoot":"","sources":["../../AutoCollection/RequestParser.ts"],"names":[],"mappings":";AAAA;;;GAGG;AACH;IAAA;IA2CA,CAAC;IAnCG;;OAEG;IACI,8BAAM,GAAb;QACI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;IACpB,CAAC;IAES,qCAAa,GAAvB;QACI,IAAI,CAAC,SAAS,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;IACjC,CAAC;IAES,kCAAU,GAApB,UAAqB,MAAc,EAAE,KAAqB;QACtD,IAAI,OAAO,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;QAC1B,IAAI,CAAC,QAAQ,GAAG,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC;QACzC,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC;QAEzB,IAAI,UAAU,GAA4B,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC;QAChE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;YACR,EAAE,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC;gBAC5B,UAAU,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC;YAChC,CAAC;YAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC;gBAChC,UAAU,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC;YACxC,CAAC;YAAC,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACnC,GAAG,CAAC,CAAC,IAAI,GAAG,IAAS,KAAK,CAAC,CAAC,CAAC;oBACzB,UAAU,CAAC,GAAG,CAAC,GAAS,KAAM,CAAC,GAAG,CAAC,IAAU,KAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,IAAU,KAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC;gBACtG,CAAC;YACL,CAAC;QACL,CAAC;QAED,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IACjC,CAAC;IAES,kCAAU,GAApB;QACI,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,GAAG,CAAC,CAAC;IAC5D,CAAC;IACL,oBAAC;AAAD,CAAC,AA3CD,IA2CC;AAED,iBAAS,aAAa,CAAC","sourcesContent":["/**\r\n * Base class for helpers that read data from HTTP request/response objects and convert them\r\n * into the telemetry contract objects.\r\n */\r\nabstract class RequestParser {\r\n protected method: string;\r\n protected url: string;\r\n protected startTime: number;\r\n protected duration: number;\r\n protected statusCode: number;\r\n protected properties: { [key: string]: string };\r\n\r\n /**\r\n * Gets a url parsed out from request options\r\n */\r\n public getUrl(): string {\r\n return this.url;\r\n }\r\n\r\n protected RequestParser() {\r\n this.startTime = +new Date();\r\n }\r\n\r\n protected _setStatus(status: number, error: Error | string) {\r\n let endTime = +new Date();\r\n this.duration = endTime - this.startTime;\r\n this.statusCode = status;\r\n\r\n let properties: {[key: string]: string} = this.properties || {};\r\n if (error) {\r\n if (typeof error === \"string\") {\r\n properties[\"error\"] = error;\r\n } else if (error instanceof Error) {\r\n properties[\"error\"] = error.message;\r\n } else if (typeof error === \"object\") {\r\n for (var key in <any>error) {\r\n properties[key] = (<any>error)[key] && (<any>error)[key].toString && (<any>error)[key].toString();\r\n }\r\n }\r\n }\r\n\r\n this.properties = properties;\r\n }\r\n\r\n protected _isSuccess() {\r\n return (0 < this.statusCode) && (this.statusCode < 400);\r\n }\r\n}\r\n\r\nexport = RequestParser;\r\n"]}
@@ -0,0 +1,3 @@
import { Span } from "../AsyncHooksScopeManager";
import * as Contracts from "../../Declarations/Contracts";
export declare function spanToTelemetryContract(span: Span): (Contracts.DependencyTelemetry & Contracts.RequestTelemetry) & Contracts.Identified;
@@ -0,0 +1,88 @@
"use strict";
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
var AsyncHooksScopeManager_1 = require("../AsyncHooksScopeManager");
var Constants = require("../../Declarations/Constants");
function filterSpanAttributes(attributes) {
var newAttributes = __assign({}, attributes);
Object.keys(Constants.SpanAttribute).forEach(function (key) {
delete newAttributes[key];
});
return newAttributes;
}
function spanToTelemetryContract(span) {
var id = "|" + span.context().traceId + "." + span.context().spanId + ".";
var duration = Math.round(span._duration[0] * 1e3 + span._duration[1] / 1e6);
var peerAddress = span.attributes["peer.address"] ? span.attributes["peer.address"].toString() : "";
var component = span.attributes["component"] ? span.attributes["component"].toString() : "";
var isHttp = ((component).toUpperCase() === Constants.DependencyTypeName.Http) || (!!span.attributes[Constants.SpanAttribute.HttpUrl]);
var isGrpc = (component).toLowerCase() === Constants.DependencyTypeName.Grpc;
if (isHttp) {
// Read http span attributes
var method = span.attributes[Constants.SpanAttribute.HttpMethod] || "GET";
var url = new URL(span.attributes[Constants.SpanAttribute.HttpUrl].toString());
var host = span.attributes[Constants.SpanAttribute.HttpHost] || url.host;
var port = span.attributes[Constants.SpanAttribute.HttpPort] || url.port || null;
var pathname = url.pathname || "/";
// Translate to AI Dependency format
var name_1 = method + " " + pathname;
var dependencyTypeName = Constants.DependencyTypeName.Http;
var target = port ? (host + ":" + port).toString() : host.toString();
var data = url.toString();
var resultCode = span.attributes[Constants.SpanAttribute.HttpStatusCode] || span.status.code || 0;
var success = resultCode < 400; // Status.OK
return {
id: id, name: name_1, dependencyTypeName: dependencyTypeName,
target: target, data: data,
success: success, duration: duration,
url: data,
resultCode: String(resultCode),
properties: filterSpanAttributes(span.attributes)
};
}
else if (isGrpc) {
var method = span.attributes[Constants.SpanAttribute.GrpcMethod] || "rpc";
var service = span.attributes[Constants.SpanAttribute.GrpcService];
var name_2 = service ? method + " " + service : span.name;
return {
id: id, duration: duration, name: name_2,
target: service.toString(),
data: service.toString() || name_2,
url: service.toString() || name_2,
dependencyTypeName: Constants.DependencyTypeName.Grpc,
resultCode: String(span.status.code || 0),
success: span.status.code === 0,
properties: filterSpanAttributes(span.attributes),
};
}
else {
var name_3 = span.name;
var links = span.links && span.links.map(function (link) {
return {
operation_Id: link.context.traceId,
id: link.context.spanId
};
});
return {
id: id, duration: duration, name: name_3,
target: peerAddress,
data: peerAddress || name_3,
url: peerAddress || name_3,
dependencyTypeName: span.kind === AsyncHooksScopeManager_1.SpanKind.INTERNAL ? Constants.DependencyTypeName.InProc : (component || span.name),
resultCode: String(span.status.code || 0),
success: span.status.code === 0,
properties: __assign({}, filterSpanAttributes(span.attributes), { "_MS.links": links || undefined }),
};
}
}
exports.spanToTelemetryContract = spanToTelemetryContract;
//# sourceMappingURL=SpanParser.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,5 @@
import TelemetryClient = require("../../Library/TelemetryClient");
import { IStandardEvent } from "diagnostic-channel";
import { Span } from "../AsyncHooksScopeManager";
export declare const subscriber: (event: IStandardEvent<Span>) => void;
export declare function enable(enabled: boolean, client: TelemetryClient): void;
@@ -0,0 +1,47 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var diagnostic_channel_1 = require("diagnostic-channel");
var Traceparent = require("../../Library/Traceparent");
var SpanParser = require("./SpanParser");
var AsyncHooksScopeManager_1 = require("../AsyncHooksScopeManager");
var clients = [];
exports.subscriber = function (event) {
var span = event.data;
var telemetry = SpanParser.spanToTelemetryContract(span);
var spanContext = span.context();
var traceparent = new Traceparent();
traceparent.traceId = spanContext.traceId;
traceparent.spanId = spanContext.spanId;
traceparent.traceFlag = spanContext.traceFlags.toString();
traceparent.parentId = span.parentSpanId ? "|" + spanContext.traceId + "." + span.parentSpanId + "." : null;
AsyncHooksScopeManager_1.AsyncScopeManager.with(span, function () {
clients.forEach(function (client) {
if (span.kind === AsyncHooksScopeManager_1.SpanKind.SERVER) {
// Server or Consumer
client.trackRequest(telemetry);
}
else if (span.kind === AsyncHooksScopeManager_1.SpanKind.CLIENT || span.kind === AsyncHooksScopeManager_1.SpanKind.INTERNAL) {
// Client or Producer or Internal
client.trackDependency(telemetry);
}
// else - ignore producer/consumer spans for now until it is clear how this sdk should interpret them
});
});
};
function enable(enabled, client) {
if (enabled) {
if (clients.length === 0) {
diagnostic_channel_1.channel.subscribe("azure-coretracing", exports.subscriber);
}
;
clients.push(client);
}
else {
clients = clients.filter(function (c) { return c != client; });
if (clients.length === 0) {
diagnostic_channel_1.channel.unsubscribe("azure-coretracing", exports.subscriber);
}
}
}
exports.enable = enable;
//# sourceMappingURL=azure-coretracing.sub.js.map
@@ -0,0 +1 @@
{"version":3,"file":"azure-coretracing.sub.js","sourceRoot":"","sources":["../../../AutoCollection/diagnostic-channel/azure-coretracing.sub.ts"],"names":[],"mappings":";;AAGA,yDAA6D;AAE7D,uDAA0D;AAC1D,yCAA2C;AAC3C,oEAA8E;AAE9E,IAAI,OAAO,GAAsB,EAAE,CAAC;AAEvB,QAAA,UAAU,GAAG,UAAC,KAA2B;IAClD,IAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;IACxB,IAAM,SAAS,GAAG,UAAU,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC;IAC3D,IAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;IACnC,IAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC;IACtC,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC;IAC1C,WAAW,CAAC,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC;IACxC,WAAW,CAAC,SAAS,GAAG,WAAW,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;IAC1D,WAAW,CAAC,QAAQ,GAAG,IAAI,CAAC,YAAY,GAAG,MAAI,WAAW,CAAC,OAAO,SAAI,IAAI,CAAC,YAAY,MAAG,GAAG,IAAI,CAAC;IAElG,0CAAiB,CAAC,IAAI,CAAC,IAAI,EAAE;QACzB,OAAO,CAAC,OAAO,CAAC,UAAC,MAAM;YACnB,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,iCAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;gBAChC,qBAAqB;gBACrB,MAAM,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;YACnC,CAAC;YAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,iCAAQ,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,KAAK,iCAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;gBAC1E,iCAAiC;gBACjC,MAAM,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;YACtC,CAAC;YACD,qGAAqG;QACzG,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACP,CAAC,CAAC;AAEF,gBAAuB,OAAgB,EAAE,MAAuB;IAC5D,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QACV,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;YACvB,4BAAO,CAAC,SAAS,CAAM,mBAAmB,EAAE,kBAAU,CAAC,CAAC;QAC5D,CAAC;QAAA,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzB,CAAC;IAAC,IAAI,CAAC,CAAC;QACJ,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,UAAC,CAAC,IAAK,OAAA,CAAC,IAAI,MAAM,EAAX,CAAW,CAAC,CAAC;QAC7C,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;YACvB,4BAAO,CAAC,WAAW,CAAC,mBAAmB,EAAE,kBAAU,CAAC,CAAC;QACzD,CAAC;IACL,CAAC;AACL,CAAC;AAZD,wBAYC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT license. See LICENSE file in the project root for details.\r\nimport TelemetryClient = require(\"../../Library/TelemetryClient\");\r\nimport { channel, IStandardEvent } from \"diagnostic-channel\";\r\n\r\nimport Traceparent = require(\"../../Library/Traceparent\");\r\nimport * as SpanParser from \"./SpanParser\";\r\nimport { Span, AsyncScopeManager, SpanKind } from \"../AsyncHooksScopeManager\";\r\n\r\nlet clients: TelemetryClient[] = [];\r\n\r\nexport const subscriber = (event: IStandardEvent<Span>) => {\r\n const span = event.data;\r\n const telemetry = SpanParser.spanToTelemetryContract(span);\r\n const spanContext = span.context();\r\n const traceparent = new Traceparent();\r\n traceparent.traceId = spanContext.traceId;\r\n traceparent.spanId = spanContext.spanId;\r\n traceparent.traceFlag = spanContext.traceFlags.toString();\r\n traceparent.parentId = span.parentSpanId ? `|${spanContext.traceId}.${span.parentSpanId}.` : null;\r\n\r\n AsyncScopeManager.with(span, () => {\r\n clients.forEach((client) => {\r\n if (span.kind === SpanKind.SERVER) {\r\n // Server or Consumer\r\n client.trackRequest(telemetry);\r\n } else if (span.kind === SpanKind.CLIENT || span.kind === SpanKind.INTERNAL) {\r\n // Client or Producer or Internal\r\n client.trackDependency(telemetry);\r\n }\r\n // else - ignore producer/consumer spans for now until it is clear how this sdk should interpret them\r\n });\r\n });\r\n};\r\n\r\nexport function enable(enabled: boolean, client: TelemetryClient) {\r\n if (enabled) {\r\n if (clients.length === 0) {\r\n channel.subscribe<any>(\"azure-coretracing\", subscriber);\r\n };\r\n clients.push(client);\r\n } else {\r\n clients = clients.filter((c) => c != client);\r\n if (clients.length === 0) {\r\n channel.unsubscribe(\"azure-coretracing\", subscriber);\r\n }\r\n }\r\n}\r\n"]}
@@ -0,0 +1,3 @@
import TelemetryClient = require("../../Library/TelemetryClient");
export declare function enable(enabled: boolean, client: TelemetryClient): void;
export declare function dispose(): void;
@@ -0,0 +1,48 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Contracts_1 = require("../../Declarations/Contracts");
var diagnostic_channel_1 = require("diagnostic-channel");
var clients = [];
// Mapping from bunyan levels defined at https://github.com/trentm/node-bunyan/blob/master/lib/bunyan.js#L256
var bunyanToAILevelMap = {
10: Contracts_1.SeverityLevel.Verbose,
20: Contracts_1.SeverityLevel.Verbose,
30: Contracts_1.SeverityLevel.Information,
40: Contracts_1.SeverityLevel.Warning,
50: Contracts_1.SeverityLevel.Error,
60: Contracts_1.SeverityLevel.Critical,
};
var subscriber = function (event) {
var message = event.data.result;
clients.forEach(function (client) {
var AIlevel = bunyanToAILevelMap[event.data.level];
if (message instanceof Error) {
client.trackException({ exception: (message) });
}
else {
client.trackTrace({ message: message, severity: AIlevel });
}
});
};
function enable(enabled, client) {
if (enabled) {
if (clients.length === 0) {
diagnostic_channel_1.channel.subscribe("bunyan", subscriber);
}
;
clients.push(client);
}
else {
clients = clients.filter(function (c) { return c != client; });
if (clients.length === 0) {
diagnostic_channel_1.channel.unsubscribe("bunyan", subscriber);
}
}
}
exports.enable = enable;
function dispose() {
diagnostic_channel_1.channel.unsubscribe("bunyan", subscriber);
clients = [];
}
exports.dispose = dispose;
//# sourceMappingURL=bunyan.sub.js.map
@@ -0,0 +1 @@
{"version":3,"file":"bunyan.sub.js","sourceRoot":"","sources":["../../../AutoCollection/diagnostic-channel/bunyan.sub.ts"],"names":[],"mappings":";;AAGA,0DAA2D;AAE3D,yDAA2D;AAI3D,IAAI,OAAO,GAAsB,EAAE,CAAC;AAEpC,6GAA6G;AAC7G,IAAM,kBAAkB,GAA6B;IACjD,EAAE,EAAE,yBAAa,CAAC,OAAO;IACzB,EAAE,EAAE,yBAAa,CAAC,OAAO;IACzB,EAAE,EAAE,yBAAa,CAAC,WAAW;IAC7B,EAAE,EAAE,yBAAa,CAAC,OAAO;IACzB,EAAE,EAAE,yBAAa,CAAC,KAAK;IACvB,EAAE,EAAE,yBAAa,CAAC,QAAQ;CAC7B,CAAC;AAEF,IAAM,UAAU,GAAG,UAAC,KAAyC;IACzD,IAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,MAAwB,CAAC;IACpD,OAAO,CAAC,OAAO,CAAC,UAAC,MAAM;QACnB,IAAM,OAAO,GAAG,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrD,EAAE,CAAC,CAAC,OAAO,YAAY,KAAK,CAAC,CAAC,CAAC;YAC3B,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACpD,CAAC;QAAC,IAAI,CAAC,CAAC;YACJ,MAAM,CAAC,UAAU,CAAC,EAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAC,CAAC,CAAC;QAC7D,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC,CAAC;AAEF,gBAAuB,OAAgB,EAAE,MAAuB;IAC5D,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QACV,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;YACvB,4BAAO,CAAC,SAAS,CAAqB,QAAQ,EAAE,UAAU,CAAC,CAAC;QAChE,CAAC;QAAA,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzB,CAAC;IAAC,IAAI,CAAC,CAAC;QACJ,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,UAAC,CAAC,IAAK,OAAA,CAAC,IAAI,MAAM,EAAX,CAAW,CAAC,CAAC;QAC7C,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;YACvB,4BAAO,CAAC,WAAW,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAC9C,CAAC;IACL,CAAC;AACL,CAAC;AAZD,wBAYC;AAED;IACI,4BAAO,CAAC,WAAW,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAC1C,OAAO,GAAG,EAAE,CAAC;AACjB,CAAC;AAHD,0BAGC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT license. See LICENSE file in the project root for details.\r\nimport TelemetryClient = require(\"../../Library/TelemetryClient\");\r\nimport {SeverityLevel} from \"../../Declarations/Contracts\";\r\n\r\nimport {channel, IStandardEvent} from \"diagnostic-channel\";\r\n\r\nimport {bunyan} from \"diagnostic-channel-publishers\";\r\n\r\nlet clients: TelemetryClient[] = [];\r\n\r\n// Mapping from bunyan levels defined at https://github.com/trentm/node-bunyan/blob/master/lib/bunyan.js#L256\r\nconst bunyanToAILevelMap: {[key: number] : number} = {\r\n 10: SeverityLevel.Verbose,\r\n 20: SeverityLevel.Verbose,\r\n 30: SeverityLevel.Information,\r\n 40: SeverityLevel.Warning,\r\n 50: SeverityLevel.Error,\r\n 60: SeverityLevel.Critical,\r\n};\r\n\r\nconst subscriber = (event: IStandardEvent<bunyan.IBunyanData>) => {\r\n const message = event.data.result as Error | string;\r\n clients.forEach((client) => {\r\n const AIlevel = bunyanToAILevelMap[event.data.level];\r\n if (message instanceof Error) {\r\n client.trackException({ exception: (message) });\r\n } else {\r\n client.trackTrace({message: message, severity: AIlevel});\r\n }\r\n });\r\n};\r\n\r\nexport function enable(enabled: boolean, client: TelemetryClient) {\r\n if (enabled) {\r\n if (clients.length === 0) {\r\n channel.subscribe<bunyan.IBunyanData>(\"bunyan\", subscriber);\r\n };\r\n clients.push(client);\r\n } else {\r\n clients = clients.filter((c) => c != client);\r\n if (clients.length === 0) {\r\n channel.unsubscribe(\"bunyan\", subscriber);\r\n }\r\n }\r\n}\r\n\r\nexport function dispose() {\r\n channel.unsubscribe(\"bunyan\", subscriber);\r\n clients = [];\r\n}\r\n"]}
@@ -0,0 +1,3 @@
import TelemetryClient = require("../../Library/TelemetryClient");
export declare function enable(enabled: boolean, client: TelemetryClient): void;
export declare function dispose(): void;
@@ -0,0 +1,42 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Contracts_1 = require("../../Declarations/Contracts");
var diagnostic_channel_1 = require("diagnostic-channel");
var clients = [];
var subscriber = function (event) {
var message = event.data.message;
clients.forEach(function (client) {
if (message instanceof Error) {
client.trackException({ exception: message });
}
else {
// Message can have a trailing newline
if (message.lastIndexOf("\n") == message.length - 1) {
message = message.substring(0, message.length - 1);
}
client.trackTrace({ message: message, severity: (event.data.stderr ? Contracts_1.SeverityLevel.Warning : Contracts_1.SeverityLevel.Information) });
}
});
};
function enable(enabled, client) {
if (enabled) {
if (clients.length === 0) {
diagnostic_channel_1.channel.subscribe("console", subscriber);
}
;
clients.push(client);
}
else {
clients = clients.filter(function (c) { return c != client; });
if (clients.length === 0) {
diagnostic_channel_1.channel.unsubscribe("console", subscriber);
}
}
}
exports.enable = enable;
function dispose() {
diagnostic_channel_1.channel.unsubscribe("console", subscriber);
clients = [];
}
exports.dispose = dispose;
//# sourceMappingURL=console.sub.js.map
@@ -0,0 +1 @@
{"version":3,"file":"console.sub.js","sourceRoot":"","sources":["../../../AutoCollection/diagnostic-channel/console.sub.ts"],"names":[],"mappings":";;AAGA,0DAA2D;AAE3D,yDAA2D;AAI3D,IAAI,OAAO,GAAsB,EAAE,CAAC;AAEpC,IAAM,UAAU,GAAG,UAAC,KAA8C;IAC9D,IAAI,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,OAAyB,CAAC;IACnD,OAAO,CAAC,OAAO,CAAC,UAAC,MAAM;QACnB,EAAE,CAAC,CAAC,OAAO,YAAY,KAAK,CAAC,CAAC,CAAC;YAC3B,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,OAAO,EAAC,CAAC,CAAC;QACjD,CAAC;QAAC,IAAI,CAAC,CAAC;YACJ,sCAAsC;YACtC,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;gBAClD,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACvD,CAAC;YACD,MAAM,CAAC,UAAU,CAAC,EAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,yBAAa,CAAC,OAAO,GAAG,yBAAa,CAAC,WAAW,CAAC,EAAC,CAAC,CAAC;QAC7H,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC,CAAC;AAEF,gBAAuB,OAAgB,EAAE,MAAuB;IAC5D,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QACV,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;YACvB,4BAAO,CAAC,SAAS,CAA0B,SAAS,EAAE,UAAU,CAAC,CAAC;QACtE,CAAC;QAAA,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzB,CAAC;IAAC,IAAI,CAAC,CAAC;QACJ,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,UAAC,CAAC,IAAK,OAAA,CAAC,IAAI,MAAM,EAAX,CAAW,CAAC,CAAC;QAC7C,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;YACvB,4BAAO,CAAC,WAAW,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QAC/C,CAAC;IACL,CAAC;AACL,CAAC;AAZD,wBAYC;AAED;IACI,4BAAO,CAAC,WAAW,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAC3C,OAAO,GAAG,EAAE,CAAC;AACjB,CAAC;AAHD,0BAGC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT license. See LICENSE file in the project root for details.\r\nimport TelemetryClient = require(\"../../Library/TelemetryClient\");\r\nimport {SeverityLevel} from \"../../Declarations/Contracts\";\r\n\r\nimport {channel, IStandardEvent} from \"diagnostic-channel\";\r\n\r\nimport {console as consolePub} from \"diagnostic-channel-publishers\";\r\n\r\nlet clients: TelemetryClient[] = [];\r\n\r\nconst subscriber = (event: IStandardEvent<consolePub.IConsoleData>) => {\r\n let message = event.data.message as Error | string;\r\n clients.forEach((client) => {\r\n if (message instanceof Error) {\r\n client.trackException({ exception: message});\r\n } else {\r\n // Message can have a trailing newline\r\n if (message.lastIndexOf(\"\\n\") == message.length - 1) {\r\n message = message.substring(0, message.length - 1);\r\n }\r\n client.trackTrace({message: message, severity: (event.data.stderr ? SeverityLevel.Warning : SeverityLevel.Information)});\r\n }\r\n });\r\n};\r\n\r\nexport function enable(enabled: boolean, client: TelemetryClient) {\r\n if (enabled) {\r\n if (clients.length === 0) {\r\n channel.subscribe<consolePub.IConsoleData>(\"console\", subscriber);\r\n };\r\n clients.push(client);\r\n } else {\r\n clients = clients.filter((c) => c != client);\r\n if (clients.length === 0) {\r\n channel.unsubscribe(\"console\", subscriber);\r\n }\r\n }\r\n}\r\n\r\nexport function dispose() {\r\n channel.unsubscribe(\"console\", subscriber);\r\n clients = [];\r\n}\r\n"]}
@@ -0,0 +1,2 @@
export declare const IsInitialized: boolean;
export declare function registerContextPreservation(cb: (cb: Function) => Function): void;
@@ -0,0 +1,47 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
Object.defineProperty(exports, "__esModule", { value: true });
var AsyncHooksScopeManager_1 = require("../AsyncHooksScopeManager");
var Logging = require("../../Library/Logging");
exports.IsInitialized = !process.env["APPLICATION_INSIGHTS_NO_DIAGNOSTIC_CHANNEL"];
var TAG = "DiagnosticChannel";
if (exports.IsInitialized) {
var publishers = require("diagnostic-channel-publishers");
var individualOptOuts = process.env["APPLICATION_INSIGHTS_NO_PATCH_MODULES"] || "";
var unpatchedModules = individualOptOuts.split(",");
var modules = {
bunyan: publishers.bunyan,
console: publishers.console,
mongodb: publishers.mongodb,
mongodbCore: publishers.mongodbCore,
mysql: publishers.mysql,
redis: publishers.redis,
pg: publishers.pg,
pgPool: publishers.pgPool,
winston: publishers.winston,
azuresdk: publishers.azuresdk
};
for (var mod in modules) {
if (unpatchedModules.indexOf(mod) === -1) {
modules[mod].enable();
Logging.info(TAG, "Subscribed to " + mod + " events");
}
}
if (unpatchedModules.length > 0) {
Logging.info(TAG, "Some modules will not be patched", unpatchedModules);
}
}
else {
Logging.info(TAG, "Not subscribing to dependency autocollection because APPLICATION_INSIGHTS_NO_DIAGNOSTIC_CHANNEL was set");
}
function registerContextPreservation(cb) {
if (!exports.IsInitialized) {
return;
}
var diagChannel = require("diagnostic-channel");
diagChannel.channel.addContextPreservation(cb);
diagChannel.channel.spanContextPropagator = AsyncHooksScopeManager_1.AsyncScopeManager;
}
exports.registerContextPreservation = registerContextPreservation;
//# sourceMappingURL=initialization.js.map
@@ -0,0 +1 @@
{"version":3,"file":"initialization.js","sourceRoot":"","sources":["../../../AutoCollection/diagnostic-channel/initialization.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,oFAAoF;;AAMpF,oEAA8D;AAC9D,+CAAkD;AAErC,QAAA,aAAa,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;AACxF,IAAM,GAAG,GAAG,mBAAmB,CAAC;AAEhC,EAAE,CAAC,CAAC,qBAAa,CAAC,CAAC,CAAC;IAChB,IAAM,UAAU,GAAiC,OAAO,CAAC,+BAA+B,CAAC,CAAC;IAC1F,IAAM,iBAAiB,GAAW,OAAO,CAAC,GAAG,CAAC,uCAAuC,CAAC,IAAI,EAAE,CAAC;IAC7F,IAAM,gBAAgB,GAAG,iBAAiB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACtD,IAAM,OAAO,GAA0B;QACnC,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,OAAO,EAAE,UAAU,CAAC,OAAO;QAC3B,OAAO,EAAE,UAAU,CAAC,OAAO;QAC3B,WAAW,EAAE,UAAU,CAAC,WAAW;QACnC,KAAK,EAAE,UAAU,CAAC,KAAK;QACvB,KAAK,EAAE,UAAU,CAAC,KAAK;QACvB,EAAE,EAAE,UAAU,CAAC,EAAE;QACjB,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,OAAO,EAAE,UAAU,CAAC,OAAO;QAC3B,QAAQ,EAAE,UAAU,CAAC,QAAQ;KAChC,CAAC;IACF,GAAG,CAAC,CAAC,IAAM,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC;QACxB,EAAE,CAAC,CAAC,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YACvC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC;YACtB,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,mBAAiB,GAAG,YAAS,CAAC,CAAC;QACrD,CAAC;IACL,CAAC;IACD,EAAE,CAAC,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QAC9B,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,kCAAkC,EAAE,gBAAgB,CAAC,CAAC;IAC5E,CAAC;AACL,CAAC;AAAC,IAAI,CAAC,CAAC;IACJ,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,yGAAyG,CAAC,CAAC;AACjI,CAAC;AAED,qCAA4C,EAA8B;IACtE,EAAE,CAAC,CAAC,CAAC,qBAAa,CAAC,CAAC,CAAC;QACjB,MAAM,CAAC;IACX,CAAC;IACD,IAAM,WAAW,GAAI,OAAO,CAAC,oBAAoB,CAAwB,CAAC;IAC1E,WAAW,CAAC,OAAO,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC;IAC/C,WAAW,CAAC,OAAO,CAAC,qBAAqB,GAAG,0CAAiB,CAAC;AAClE,CAAC;AAPD,kEAOC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT license. See LICENSE file in the project root for details.\r\n\r\n// Don't reference modules from these directly. Use only for types.\r\n// This is to avoid requiring the actual module if the NO_DIAGNOSTIC_CHANNEL env is present\r\nimport * as DiagChannelPublishers from \"diagnostic-channel-publishers\";\r\nimport * as DiagChannel from \"diagnostic-channel\";\r\nimport { AsyncScopeManager } from \"../AsyncHooksScopeManager\";\r\nimport Logging = require(\"../../Library/Logging\");\r\n\r\nexport const IsInitialized = !process.env[\"APPLICATION_INSIGHTS_NO_DIAGNOSTIC_CHANNEL\"];\r\nconst TAG = \"DiagnosticChannel\";\r\n\r\nif (IsInitialized) {\r\n const publishers: typeof DiagChannelPublishers = require(\"diagnostic-channel-publishers\");\r\n const individualOptOuts: string = process.env[\"APPLICATION_INSIGHTS_NO_PATCH_MODULES\"] || \"\";\r\n const unpatchedModules = individualOptOuts.split(\",\");\r\n const modules: {[key: string] : any} = {\r\n bunyan: publishers.bunyan,\r\n console: publishers.console,\r\n mongodb: publishers.mongodb,\r\n mongodbCore: publishers.mongodbCore,\r\n mysql: publishers.mysql,\r\n redis: publishers.redis,\r\n pg: publishers.pg,\r\n pgPool: publishers.pgPool,\r\n winston: publishers.winston,\r\n azuresdk: publishers.azuresdk\r\n };\r\n for (const mod in modules) {\r\n if (unpatchedModules.indexOf(mod) === -1) {\r\n modules[mod].enable();\r\n Logging.info(TAG, `Subscribed to ${mod} events`);\r\n }\r\n }\r\n if (unpatchedModules.length > 0) {\r\n Logging.info(TAG, \"Some modules will not be patched\", unpatchedModules);\r\n }\r\n} else {\r\n Logging.info(TAG, \"Not subscribing to dependency autocollection because APPLICATION_INSIGHTS_NO_DIAGNOSTIC_CHANNEL was set\");\r\n}\r\n\r\nexport function registerContextPreservation(cb: (cb: Function) => Function) {\r\n if (!IsInitialized) {\r\n return;\r\n }\r\n const diagChannel = (require(\"diagnostic-channel\") as typeof DiagChannel);\r\n diagChannel.channel.addContextPreservation(cb);\r\n diagChannel.channel.spanContextPropagator = AsyncScopeManager;\r\n}\r\n"]}
@@ -0,0 +1,5 @@
import TelemetryClient = require("../../Library/TelemetryClient");
import { IStandardEvent } from "diagnostic-channel";
import { mongodb } from "diagnostic-channel-publishers";
export declare const subscriber: (event: IStandardEvent<mongodb.IMongoData>) => void;
export declare function enable(enabled: boolean, client: TelemetryClient): void;
@@ -0,0 +1,41 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var diagnostic_channel_1 = require("diagnostic-channel");
var clients = [];
exports.subscriber = function (event) {
if (event.data.event.commandName === "ismaster") {
// suppress noisy ismaster commands
return;
}
clients.forEach(function (client) {
var dbName = (event.data.startedData && event.data.startedData.databaseName) || "Unknown database";
client.trackDependency({
target: dbName,
data: event.data.event.commandName,
name: event.data.event.commandName,
duration: event.data.event.duration,
success: event.data.succeeded,
/* TODO: transmit result code from mongo */
resultCode: event.data.succeeded ? "0" : "1",
time: event.data.startedData.time,
dependencyTypeName: 'mongodb'
});
});
};
function enable(enabled, client) {
if (enabled) {
if (clients.length === 0) {
diagnostic_channel_1.channel.subscribe("mongodb", exports.subscriber);
}
;
clients.push(client);
}
else {
clients = clients.filter(function (c) { return c != client; });
if (clients.length === 0) {
diagnostic_channel_1.channel.unsubscribe("mongodb", exports.subscriber);
}
}
}
exports.enable = enable;
//# sourceMappingURL=mongodb.sub.js.map
@@ -0,0 +1 @@
{"version":3,"file":"mongodb.sub.js","sourceRoot":"","sources":["../../../AutoCollection/diagnostic-channel/mongodb.sub.ts"],"names":[],"mappings":";;AAGA,yDAA6D;AAI7D,IAAI,OAAO,GAAsB,EAAE,CAAC;AAEvB,QAAA,UAAU,GAAG,UAAC,KAAyC;IAChE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC;QAC9C,mCAAmC;QACnC,MAAM,CAAC;IACX,CAAC;IACD,OAAO,CAAC,OAAO,CAAC,UAAC,MAAM;QACnB,IAAM,MAAM,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,IAAI,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,IAAI,kBAAkB,CAAC;QACrG,MAAM,CAAC,eAAe,CAClB;YACI,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW;YAClC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW;YAClC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ;YACnC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,SAAS;YAC7B,2CAA2C;YAC3C,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,SAAS,GAAG,GAAG,GAAG,GAAG;YAC5C,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI;YACjC,kBAAkB,EAAE,SAAS;SAChC,CAAC,CAAC;IACX,CAAC,CAAC,CAAC;AACP,CAAC,CAAC;AAEF,gBAAuB,OAAgB,EAAE,MAAuB;IAC5D,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QACV,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;YACvB,4BAAO,CAAC,SAAS,CAAqB,SAAS,EAAE,kBAAU,CAAC,CAAC;QACjE,CAAC;QAAA,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzB,CAAC;IAAC,IAAI,CAAC,CAAC;QACJ,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,UAAC,CAAC,IAAK,OAAA,CAAC,IAAI,MAAM,EAAX,CAAW,CAAC,CAAC;QAC7C,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;YACvB,4BAAO,CAAC,WAAW,CAAC,SAAS,EAAE,kBAAU,CAAC,CAAC;QAC/C,CAAC;IACL,CAAC;AACL,CAAC;AAZD,wBAYC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT license. See LICENSE file in the project root for details.\r\nimport TelemetryClient = require(\"../../Library/TelemetryClient\");\r\nimport { channel, IStandardEvent } from \"diagnostic-channel\";\r\n\r\nimport { mongodb } from \"diagnostic-channel-publishers\";\r\n\r\nlet clients: TelemetryClient[] = [];\r\n\r\nexport const subscriber = (event: IStandardEvent<mongodb.IMongoData>) => {\r\n if (event.data.event.commandName === \"ismaster\") {\r\n // suppress noisy ismaster commands\r\n return;\r\n }\r\n clients.forEach((client) => {\r\n const dbName = (event.data.startedData && event.data.startedData.databaseName) || \"Unknown database\";\r\n client.trackDependency(\r\n {\r\n target: dbName,\r\n data: event.data.event.commandName,\r\n name: event.data.event.commandName,\r\n duration: event.data.event.duration,\r\n success: event.data.succeeded,\r\n /* TODO: transmit result code from mongo */\r\n resultCode: event.data.succeeded ? \"0\" : \"1\",\r\n time: event.data.startedData.time,\r\n dependencyTypeName: 'mongodb'\r\n });\r\n });\r\n};\r\n\r\nexport function enable(enabled: boolean, client: TelemetryClient) {\r\n if (enabled) {\r\n if (clients.length === 0) {\r\n channel.subscribe<mongodb.IMongoData>(\"mongodb\", subscriber);\r\n };\r\n clients.push(client);\r\n } else {\r\n clients = clients.filter((c) => c != client);\r\n if (clients.length === 0) {\r\n channel.unsubscribe(\"mongodb\", subscriber);\r\n }\r\n }\r\n}\r\n"]}
@@ -0,0 +1,5 @@
import TelemetryClient = require("../../Library/TelemetryClient");
import { IStandardEvent } from "diagnostic-channel";
import { mysql } from "diagnostic-channel-publishers";
export declare const subscriber: (event: IStandardEvent<mysql.IMysqlData>) => void;
export declare function enable(enabled: boolean, client: TelemetryClient): void;
@@ -0,0 +1,42 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var diagnostic_channel_1 = require("diagnostic-channel");
var clients = [];
exports.subscriber = function (event) {
clients.forEach(function (client) {
var queryObj = event.data.query || {};
var sqlString = queryObj.sql || "Unknown query";
var success = !event.data.err;
var connection = queryObj._connection || {};
var connectionConfig = connection.config || {};
var dbName = connectionConfig.socketPath ? connectionConfig.socketPath : (connectionConfig.host || "localhost") + ":" + connectionConfig.port;
client.trackDependency({
target: dbName,
data: sqlString,
name: sqlString,
duration: event.data.duration,
success: success,
/* TODO: transmit result code from mysql */
resultCode: success ? "0" : "1",
time: event.data.time,
dependencyTypeName: "mysql"
});
});
};
function enable(enabled, client) {
if (enabled) {
if (clients.length === 0) {
diagnostic_channel_1.channel.subscribe("mysql", exports.subscriber);
}
;
clients.push(client);
}
else {
clients = clients.filter(function (c) { return c != client; });
if (clients.length === 0) {
diagnostic_channel_1.channel.unsubscribe("mysql", exports.subscriber);
}
}
}
exports.enable = enable;
//# sourceMappingURL=mysql.sub.js.map
@@ -0,0 +1 @@
{"version":3,"file":"mysql.sub.js","sourceRoot":"","sources":["../../../AutoCollection/diagnostic-channel/mysql.sub.ts"],"names":[],"mappings":";;AAGA,yDAA2D;AAI3D,IAAI,OAAO,GAAsB,EAAE,CAAC;AAEvB,QAAA,UAAU,GAAG,UAAC,KAAuC;IAC9D,OAAO,CAAC,OAAO,CAAC,UAAC,MAAM;QACnB,IAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;QACxC,IAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,IAAI,eAAe,CAAC;QAClD,IAAM,OAAO,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;QAEhC,IAAM,UAAU,GAAG,QAAQ,CAAC,WAAW,IAAI,EAAE,CAAC;QAC9C,IAAM,gBAAgB,GAAG,UAAU,CAAC,MAAM,IAAI,EAAE,CAAC;QACjD,IAAM,MAAM,GAAG,gBAAgB,CAAC,UAAU,GAAG,gBAAgB,CAAC,UAAU,GAAG,CAAG,gBAAgB,CAAC,IAAI,IAAI,WAAW,UAAI,gBAAgB,CAAC,IAAM,CAAC;QAC9I,MAAM,CAAC,eAAe,CAClB;YACI,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,SAAS;YACf,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ;YAC7B,OAAO,EAAE,OAAO;YAChB,2CAA2C;YAC3C,UAAU,EAAE,OAAO,GAAE,GAAG,GAAE,GAAG;YAC7B,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI;YACrB,kBAAkB,EAAE,OAAO;SAC9B,CAAC,CAAC;IACX,CAAC,CAAC,CAAC;AACP,CAAC,CAAC;AAEF,gBAAuB,OAAgB,EAAE,MAAuB;IAC5D,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QACV,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;YACvB,4BAAO,CAAC,SAAS,CAAmB,OAAO,EAAE,kBAAU,CAAC,CAAC;QAC7D,CAAC;QAAA,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzB,CAAC;IAAC,IAAI,CAAC,CAAC;QACJ,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,UAAC,CAAC,IAAK,OAAA,CAAC,IAAI,MAAM,EAAX,CAAW,CAAC,CAAC;QAC7C,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;YACvB,4BAAO,CAAC,WAAW,CAAC,OAAO,EAAE,kBAAU,CAAC,CAAC;QAC7C,CAAC;IACL,CAAC;AACL,CAAC;AAZD,wBAYC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT license. See LICENSE file in the project root for details.\r\nimport TelemetryClient = require(\"../../Library/TelemetryClient\");\r\nimport {channel, IStandardEvent} from \"diagnostic-channel\";\r\n\r\nimport {mysql} from \"diagnostic-channel-publishers\";\r\n\r\nlet clients: TelemetryClient[] = [];\r\n\r\nexport const subscriber = (event: IStandardEvent<mysql.IMysqlData>) => {\r\n clients.forEach((client) => {\r\n const queryObj = event.data.query || {};\r\n const sqlString = queryObj.sql || \"Unknown query\";\r\n const success = !event.data.err;\r\n\r\n const connection = queryObj._connection || {};\r\n const connectionConfig = connection.config || {};\r\n const dbName = connectionConfig.socketPath ? connectionConfig.socketPath : `${connectionConfig.host || \"localhost\"}:${connectionConfig.port}`;\r\n client.trackDependency(\r\n {\r\n target: dbName,\r\n data: sqlString,\r\n name: sqlString,\r\n duration: event.data.duration,\r\n success: success,\r\n /* TODO: transmit result code from mysql */\r\n resultCode: success? \"0\": \"1\",\r\n time: event.data.time,\r\n dependencyTypeName: \"mysql\"\r\n });\r\n });\r\n};\r\n\r\nexport function enable(enabled: boolean, client: TelemetryClient) {\r\n if (enabled) {\r\n if (clients.length === 0) {\r\n channel.subscribe<mysql.IMysqlData>(\"mysql\", subscriber);\r\n };\r\n clients.push(client);\r\n } else {\r\n clients = clients.filter((c) => c != client);\r\n if (clients.length === 0) {\r\n channel.unsubscribe(\"mysql\", subscriber);\r\n }\r\n }\r\n}\r\n"]}
@@ -0,0 +1,5 @@
import TelemetryClient = require("../../Library/TelemetryClient");
import { IStandardEvent } from "diagnostic-channel";
import { pg } from "diagnostic-channel-publishers";
export declare const subscriber: (event: IStandardEvent<pg.IPostgresData>) => void;
export declare function enable(enabled: boolean, client: TelemetryClient): void;
@@ -0,0 +1,39 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var diagnostic_channel_1 = require("diagnostic-channel");
var clients = [];
exports.subscriber = function (event) {
clients.forEach(function (client) {
var q = event.data.query;
var sql = (q.preparable && q.preparable.text) || q.plan || q.text || "unknown query";
var success = !event.data.error;
var conn = event.data.database.host + ":" + event.data.database.port;
client.trackDependency({
target: conn,
data: sql,
name: sql,
duration: event.data.duration,
success: success,
resultCode: success ? "0" : "1",
time: event.data.time,
dependencyTypeName: "postgres"
});
});
};
function enable(enabled, client) {
if (enabled) {
if (clients.length === 0) {
diagnostic_channel_1.channel.subscribe("postgres", exports.subscriber);
}
;
clients.push(client);
}
else {
clients = clients.filter(function (c) { return c != client; });
if (clients.length === 0) {
diagnostic_channel_1.channel.unsubscribe("postgres", exports.subscriber);
}
}
}
exports.enable = enable;
//# sourceMappingURL=postgres.sub.js.map
@@ -0,0 +1 @@
{"version":3,"file":"postgres.sub.js","sourceRoot":"","sources":["../../../AutoCollection/diagnostic-channel/postgres.sub.ts"],"names":[],"mappings":";;AAGA,yDAA6D;AAI7D,IAAI,OAAO,GAAsB,EAAE,CAAC;AAEvB,QAAA,UAAU,GAAG,UAAC,KAAuC;IAC9D,OAAO,CAAC,OAAO,CAAC,UAAC,MAAM;QACnB,IAAM,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;QAC3B,IAAM,GAAG,GAAG,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,eAAe,CAAC;QACvF,IAAM,OAAO,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;QAClC,IAAM,IAAI,GAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,SAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAM,CAAC;QACvE,MAAM,CAAC,eAAe,CAAC;YACnB,MAAM,EAAE,IAAI;YACZ,IAAI,EAAE,GAAG;YACT,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ;YAC7B,OAAO,EAAE,OAAO;YAChB,UAAU,EAAE,OAAO,GAAG,GAAG,GAAG,GAAG;YAC/B,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI;YACrB,kBAAkB,EAAE,UAAU;SAAC,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;AACP,CAAC,CAAC;AAEF,gBAAuB,OAAgB,EAAE,MAAuB;IAC5D,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QACV,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;YACvB,4BAAO,CAAC,SAAS,CAAmB,UAAU,EAAE,kBAAU,CAAC,CAAC;QAChE,CAAC;QAAA,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzB,CAAC;IAAC,IAAI,CAAC,CAAC;QACJ,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,UAAC,CAAC,IAAK,OAAA,CAAC,IAAI,MAAM,EAAX,CAAW,CAAC,CAAC;QAC7C,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;YACvB,4BAAO,CAAC,WAAW,CAAC,UAAU,EAAE,kBAAU,CAAC,CAAC;QAChD,CAAC;IACL,CAAC;AACL,CAAC;AAZD,wBAYC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT license. See LICENSE file in the project root for details.\r\nimport TelemetryClient = require(\"../../Library/TelemetryClient\");\r\nimport { channel, IStandardEvent } from \"diagnostic-channel\";\r\n\r\nimport { pg } from \"diagnostic-channel-publishers\";\r\n\r\nlet clients: TelemetryClient[] = [];\r\n\r\nexport const subscriber = (event: IStandardEvent<pg.IPostgresData>) => {\r\n clients.forEach((client) => {\r\n const q = event.data.query;\r\n const sql = (q.preparable && q.preparable.text) || q.plan || q.text || \"unknown query\";\r\n const success = !event.data.error;\r\n const conn = `${event.data.database.host}:${event.data.database.port}`;\r\n client.trackDependency({\r\n target: conn,\r\n data: sql,\r\n name: sql,\r\n duration: event.data.duration,\r\n success: success,\r\n resultCode: success ? \"0\" : \"1\",\r\n time: event.data.time,\r\n dependencyTypeName: \"postgres\"});\r\n });\r\n};\r\n\r\nexport function enable(enabled: boolean, client: TelemetryClient) {\r\n if (enabled) {\r\n if (clients.length === 0) {\r\n channel.subscribe<pg.IPostgresData>(\"postgres\", subscriber);\r\n };\r\n clients.push(client);\r\n } else {\r\n clients = clients.filter((c) => c != client);\r\n if (clients.length === 0) {\r\n channel.unsubscribe(\"postgres\", subscriber);\r\n }\r\n }\r\n}\r\n"]}
@@ -0,0 +1,5 @@
import TelemetryClient = require("../../Library/TelemetryClient");
import { IStandardEvent } from "diagnostic-channel";
import { redis } from "diagnostic-channel-publishers";
export declare const subscriber: (event: IStandardEvent<redis.IRedisData>) => void;
export declare function enable(enabled: boolean, client: TelemetryClient): void;
@@ -0,0 +1,40 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var diagnostic_channel_1 = require("diagnostic-channel");
var clients = [];
exports.subscriber = function (event) {
clients.forEach(function (client) {
if (event.data.commandObj.command === "info") {
// We don't want to report 'info', it's irrelevant
return;
}
client.trackDependency({
target: event.data.address,
name: event.data.commandObj.command,
data: event.data.commandObj.command,
duration: event.data.duration,
success: !event.data.err,
/* TODO: transmit result code from redis */
resultCode: event.data.err ? "1" : "0",
time: event.data.time,
dependencyTypeName: "redis"
});
});
};
function enable(enabled, client) {
if (enabled) {
if (clients.length === 0) {
diagnostic_channel_1.channel.subscribe("redis", exports.subscriber);
}
;
clients.push(client);
}
else {
clients = clients.filter(function (c) { return c != client; });
if (clients.length === 0) {
diagnostic_channel_1.channel.unsubscribe("redis", exports.subscriber);
}
}
}
exports.enable = enable;
//# sourceMappingURL=redis.sub.js.map
@@ -0,0 +1 @@
{"version":3,"file":"redis.sub.js","sourceRoot":"","sources":["../../../AutoCollection/diagnostic-channel/redis.sub.ts"],"names":[],"mappings":";;AAGA,yDAA6D;AAI7D,IAAI,OAAO,GAAsB,EAAE,CAAC;AAEvB,QAAA,UAAU,GAAG,UAAC,KAAuC;IAC9D,OAAO,CAAC,OAAO,CAAC,UAAC,MAAM;QACnB,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC;YAC3C,kDAAkD;YAClD,MAAM,CAAC;QACX,CAAC;QACD,MAAM,CAAC,eAAe,CAClB;YACI,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,OAAO;YAC1B,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO;YACnC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO;YACnC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ;YAC7B,OAAO,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG;YACxB,2CAA2C;YAC3C,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG;YACtC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI;YACrB,kBAAkB,EAAE,OAAO;SAC9B,CAAC,CAAC;IAEX,CAAC,CAAC,CAAC;AACP,CAAC,CAAC;AAEF,gBAAuB,OAAgB,EAAE,MAAuB;IAC5D,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QACV,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;YACvB,4BAAO,CAAC,SAAS,CAAmB,OAAO,EAAE,kBAAU,CAAC,CAAC;QAC7D,CAAC;QAAA,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzB,CAAC;IAAC,IAAI,CAAC,CAAC;QACJ,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,UAAC,CAAC,IAAK,OAAA,CAAC,IAAI,MAAM,EAAX,CAAW,CAAC,CAAC;QAC7C,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;YACvB,4BAAO,CAAC,WAAW,CAAC,OAAO,EAAE,kBAAU,CAAC,CAAC;QAC7C,CAAC;IACL,CAAC;AACL,CAAC;AAZD,wBAYC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT license. See LICENSE file in the project root for details.\r\nimport TelemetryClient = require(\"../../Library/TelemetryClient\");\r\nimport { channel, IStandardEvent } from \"diagnostic-channel\";\r\n\r\nimport { redis } from \"diagnostic-channel-publishers\";\r\n\r\nlet clients: TelemetryClient[] = [];\r\n\r\nexport const subscriber = (event: IStandardEvent<redis.IRedisData>) => {\r\n clients.forEach((client) => {\r\n if (event.data.commandObj.command === \"info\") {\r\n // We don't want to report 'info', it's irrelevant\r\n return;\r\n }\r\n client.trackDependency(\r\n {\r\n target: event.data.address,\r\n name: event.data.commandObj.command,\r\n data: event.data.commandObj.command,\r\n duration: event.data.duration,\r\n success: !event.data.err,\r\n /* TODO: transmit result code from redis */\r\n resultCode: event.data.err ? \"1\" : \"0\",\r\n time: event.data.time,\r\n dependencyTypeName: \"redis\"\r\n });\r\n\r\n });\r\n};\r\n\r\nexport function enable(enabled: boolean, client: TelemetryClient) {\r\n if (enabled) {\r\n if (clients.length === 0) {\r\n channel.subscribe<redis.IRedisData>(\"redis\", subscriber);\r\n };\r\n clients.push(client);\r\n } else {\r\n clients = clients.filter((c) => c != client);\r\n if (clients.length === 0) {\r\n channel.unsubscribe(\"redis\", subscriber);\r\n }\r\n }\r\n}\r\n"]}
@@ -0,0 +1,3 @@
import TelemetryClient = require("../../Library/TelemetryClient");
export declare function enable(enabled: boolean, client: TelemetryClient): void;
export declare function dispose(): void;
@@ -0,0 +1,75 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Contracts_1 = require("../../Declarations/Contracts");
var diagnostic_channel_1 = require("diagnostic-channel");
var clients = [];
var winstonToAILevelMap = {
syslog: function (og) {
var map = {
emerg: Contracts_1.SeverityLevel.Critical,
alert: Contracts_1.SeverityLevel.Critical,
crit: Contracts_1.SeverityLevel.Critical,
error: Contracts_1.SeverityLevel.Error,
warning: Contracts_1.SeverityLevel.Warning,
notice: Contracts_1.SeverityLevel.Information,
info: Contracts_1.SeverityLevel.Information,
debug: Contracts_1.SeverityLevel.Verbose
};
return map[og] === undefined ? Contracts_1.SeverityLevel.Information : map[og];
},
npm: function (og) {
var map = {
error: Contracts_1.SeverityLevel.Error,
warn: Contracts_1.SeverityLevel.Warning,
info: Contracts_1.SeverityLevel.Information,
verbose: Contracts_1.SeverityLevel.Verbose,
debug: Contracts_1.SeverityLevel.Verbose,
silly: Contracts_1.SeverityLevel.Verbose
};
return map[og] === undefined ? Contracts_1.SeverityLevel.Information : map[og];
},
unknown: function (og) {
return Contracts_1.SeverityLevel.Information;
}
};
var subscriber = function (event) {
var message = event.data.message;
clients.forEach(function (client) {
if (message instanceof Error) {
client.trackException({
exception: message,
properties: event.data.meta
});
}
else {
var AIlevel = winstonToAILevelMap[event.data.levelKind](event.data.level);
client.trackTrace({
message: message,
severity: AIlevel,
properties: event.data.meta
});
}
});
};
function enable(enabled, client) {
if (enabled) {
if (clients.length === 0) {
diagnostic_channel_1.channel.subscribe("winston", subscriber);
}
;
clients.push(client);
}
else {
clients = clients.filter(function (c) { return c != client; });
if (clients.length === 0) {
diagnostic_channel_1.channel.unsubscribe("winston", subscriber);
}
}
}
exports.enable = enable;
function dispose() {
diagnostic_channel_1.channel.unsubscribe("winston", subscriber);
clients = [];
}
exports.dispose = dispose;
//# sourceMappingURL=winston.sub.js.map
File diff suppressed because one or more lines are too long
+38
View File
@@ -0,0 +1,38 @@
export interface AgentLogger {
log(message?: any, ...optional: any[]): void;
error(message?: any, ...optional: any[]): void;
}
export declare const enum SeverityLevel {
ERROR = "ERROR",
WARN = "WARN",
INFO = "INFO",
}
export interface DiagnosticLog {
/**
* UTC
*/
time: string;
/**
* Log severity, INFO, WARN, ERROR
*/
level: SeverityLevel;
/**
* The logger writing this message. Usually the fully-qualified class or package name
*/
logger: string;
/**
* The log message
*/
message: string;
/**
* Exception (as string)
*/
exception?: string;
/**
* Any custom data related to the error/application/operation. Each field should have a string value
* Examples: operation, siteName, ikey, extensionVersion, sdkVersion, subscriptionId
*/
properties: {
[key: string]: string;
};
}
+4
View File
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
;
//# sourceMappingURL=DataModel.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"DataModel.js","sourceRoot":"","sources":["../../Bootstrap/DataModel.ts"],"names":[],"mappings":";;AASC,CAAC","sourcesContent":["export interface AgentLogger {\r\n log(message?: any, ...optional: any[]): void;\r\n error(message?: any, ...optional: any[]): void;\r\n}\r\n\r\nexport const enum SeverityLevel {\r\n ERROR = \"ERROR\",\r\n WARN = \"WARN\",\r\n INFO = \"INFO\"\r\n};\r\n\r\nexport interface DiagnosticLog {\r\n /**\r\n * UTC\r\n */\r\n time: string;\r\n\r\n /**\r\n * Log severity, INFO, WARN, ERROR\r\n */\r\n level: SeverityLevel;\r\n\r\n /**\r\n * The logger writing this message. Usually the fully-qualified class or package name\r\n */\r\n logger: string;\r\n\r\n /**\r\n * The log message\r\n */\r\n message: string;\r\n\r\n /**\r\n * Exception (as string)\r\n */\r\n exception?: string\r\n\r\n /**\r\n * Any custom data related to the error/application/operation. Each field should have a string value\r\n * Examples: operation, siteName, ikey, extensionVersion, sdkVersion, subscriptionId\r\n */\r\n properties: { [key: string]: string };\r\n}\r\n"]}
+19
View File
@@ -0,0 +1,19 @@
import * as types from "../applicationinsights";
import { StatusLogger } from "./StatusLogger";
import { DiagnosticLogger } from "./DiagnosticLogger";
/**
* Sets the attach-time logger
* @param logger logger which implements the `AgentLogger` interface
*/
export declare function setLogger(logger: DiagnosticLogger): DiagnosticLogger;
/**
* Sets the string which is prefixed to the existing sdkVersion, e.g. `ad_`, `alr_`
* @param prefix string prefix, including underscore. Defaults to `ad_`
*/
export declare function setUsagePrefix(prefix: string): void;
export declare function setStatusLogger(statusLogger: StatusLogger): void;
/**
* Try to setup and start this app insights instance if attach is enabled.
* @param setupString connection string or instrumentation key
*/
export declare function setupAndStart(setupString?: any): typeof types | null;
+105
View File
@@ -0,0 +1,105 @@
"use strict";
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
var Helpers = require("./Helpers");
var Constants = require("../Declarations/Constants");
var StatusLogger_1 = require("./StatusLogger");
var DiagnosticLogger_1 = require("./DiagnosticLogger");
// Private configuration vars
var _appInsights;
var _prefix = "ad_"; // App Services, Default
var _logger = new DiagnosticLogger_1.DiagnosticLogger(console);
var _statusLogger = new StatusLogger_1.StatusLogger(console);
// Env var local constants
var _setupString = process.env.APPLICATIONINSIGHTS_CONNECTION_STRING || process.env.APPINSIGHTS_INSTRUMENTATIONKEY;
var forceStart = process.env.APPLICATIONINSIGHTS_FORCE_START === "true";
// Other local constants
var defaultStatus = __assign({}, StatusLogger_1.StatusLogger.DEFAULT_STATUS, { Ikey: _setupString });
/**
* Sets the attach-time logger
* @param logger logger which implements the `AgentLogger` interface
*/
function setLogger(logger) {
return _logger = logger;
}
exports.setLogger = setLogger;
/**
* Sets the string which is prefixed to the existing sdkVersion, e.g. `ad_`, `alr_`
* @param prefix string prefix, including underscore. Defaults to `ad_`
*/
function setUsagePrefix(prefix) {
_prefix = prefix;
}
exports.setUsagePrefix = setUsagePrefix;
function setStatusLogger(statusLogger) {
_statusLogger = statusLogger;
}
exports.setStatusLogger = setStatusLogger;
/**
* Try to setup and start this app insights instance if attach is enabled.
* @param setupString connection string or instrumentation key
*/
function setupAndStart(setupString) {
if (setupString === void 0) { setupString = _setupString; }
// If app already contains SDK, skip agent attach
if (!forceStart && Helpers.sdkAlreadyExists(_logger)) {
_statusLogger.logStatus(__assign({}, defaultStatus, { AgentInitializedSuccessfully: false, SDKPresent: true, Reason: "SDK already exists" }));
return null;
}
if (!setupString) {
var message = "Application Insights wanted to be started, but no Connection String or Instrumentation Key was provided";
_logger.logError(message, setupString);
_statusLogger.logStatus(__assign({}, defaultStatus, { AgentInitializedSuccessfully: false, Reason: message }));
return null;
}
try {
_appInsights = require("../applicationinsights");
if (_appInsights.defaultClient) {
// setupAndStart was already called, return the result
_logger.logError("Setup was attempted on the Application Insights Client multiple times. Aborting and returning the first client instance");
return _appInsights;
}
var prefixInternalSdkVersion = function (envelope, _contextObjects) {
try {
var appInsightsSDKVersion = _appInsights.defaultClient.context.keys.internalSdkVersion;
envelope.tags[appInsightsSDKVersion] = _prefix + envelope.tags[appInsightsSDKVersion];
}
catch (e) {
_logger.logError("Error prefixing SDK version", e);
}
return true;
};
var copyOverPrefixInternalSdkVersionToHeartBeatMetric = function (envelope, _contextObjects) {
var appInsightsSDKVersion = _appInsights.defaultClient.context.keys.internalSdkVersion;
var sdkVersion = envelope.tags[appInsightsSDKVersion] || "";
if (envelope.name === Constants.HeartBeatMetricName) {
(envelope.data.baseData).properties = (envelope.data.baseData).properties || {};
(envelope.data.baseData).properties["sdk"] = sdkVersion;
}
return true;
};
// Instrument the SDK
_appInsights.setup(setupString).setSendLiveMetrics(true);
_appInsights.defaultClient.setAutoPopulateAzureProperties(true);
_appInsights.defaultClient.addTelemetryProcessor(prefixInternalSdkVersion);
_appInsights.defaultClient.addTelemetryProcessor(copyOverPrefixInternalSdkVersionToHeartBeatMetric);
_appInsights.start();
// Agent successfully instrumented the SDK
_logger.logMessage("Application Insights was started with setupString: " + setupString);
_statusLogger.logStatus(__assign({}, defaultStatus, { AgentInitializedSuccessfully: true }));
}
catch (e) {
_logger.logError("Error setting up Application Insights", e);
_statusLogger.logStatus(__assign({}, defaultStatus, { AgentInitializedSuccessfully: false, Reason: "Error setting up Application Insights: " + (e && e.message) }));
}
return _appInsights;
}
exports.setupAndStart = setupAndStart;
//# sourceMappingURL=Default.js.map
File diff suppressed because one or more lines are too long
+10
View File
@@ -0,0 +1,10 @@
import * as DataModel from "./DataModel";
export declare class DiagnosticLogger {
private _writer;
static readonly DEFAULT_FILE_NAME: string;
static readonly DEFAULT_LOG_DIR: string;
static DefaultEnvelope: DataModel.DiagnosticLog;
constructor(_writer?: DataModel.AgentLogger);
logMessage(message: DataModel.DiagnosticLog | string, cb?: (err: Error) => void): void;
logError(message: DataModel.DiagnosticLog | string, cb?: (err: Error) => void): void;
}
+69
View File
@@ -0,0 +1,69 @@
"use strict";
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
var path = require("path");
var DataModel = require("./DataModel");
var FileWriter_1 = require("./FileWriter");
var FileHelpers_1 = require("./Helpers/FileHelpers");
var DiagnosticLogger = (function () {
function DiagnosticLogger(_writer) {
if (_writer === void 0) { _writer = console; }
this._writer = _writer;
}
DiagnosticLogger.prototype.logMessage = function (message, cb) {
if (typeof cb === "function" && this._writer instanceof FileWriter_1.FileWriter) {
this._writer.callback = cb;
}
if (typeof message === "string") {
var diagnosticMessage = __assign({}, DiagnosticLogger.DefaultEnvelope, { message: message, level: "INFO" /* INFO */, time: new Date().toISOString() });
this._writer.log(diagnosticMessage);
}
else {
if (message.level === "ERROR" /* ERROR */) {
this._writer.error(message);
}
else {
this._writer.log(message);
}
}
};
DiagnosticLogger.prototype.logError = function (message, cb) {
if (typeof cb === "function" && this._writer instanceof FileWriter_1.FileWriter) {
this._writer.callback = cb;
}
if (typeof message === "string") {
var diagnosticMessage = __assign({}, DiagnosticLogger.DefaultEnvelope, { message: message, level: "ERROR" /* ERROR */, time: new Date().toUTCString() });
this._writer.error(diagnosticMessage);
}
else {
this._writer.error(message);
}
};
DiagnosticLogger.DEFAULT_FILE_NAME = "application-insights-extension.log";
DiagnosticLogger.DEFAULT_LOG_DIR = process.env.APPLICATIONINSIGHTS_LOGDIR || path.join(FileHelpers_1.homedir, "LogFiles/ApplicationInsights");
DiagnosticLogger.DefaultEnvelope = {
message: null,
level: null,
time: null,
logger: "applicationinsights.extension.diagnostics",
properties: {
language: "nodejs",
operation: "Startup",
siteName: process.env.WEBSITE_SITE_NAME,
ikey: process.env.APPINSIGHTS_INSTRUMENTATIONKEY,
extensionVersion: process.env.ApplicationInsightsAgent_EXTENSION_VERSION,
sdkVersion: "1.8.10",
subscriptionId: process.env.WEBSITE_OWNER_NAME ? process.env.WEBSITE_OWNER_NAME.split("+")[0] : null,
}
};
return DiagnosticLogger;
}());
exports.DiagnosticLogger = DiagnosticLogger;
//# sourceMappingURL=DiagnosticLogger.js.map
@@ -0,0 +1 @@
{"version":3,"file":"DiagnosticLogger.js","sourceRoot":"","sources":["../../Bootstrap/DiagnosticLogger.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;;;AAEb,2BAA6B;AAE7B,uCAAyC;AACzC,2CAA0C;AAC1C,qDAAgD;AAEhD;IAmBI,0BAAoB,OAAwC;QAAxC,wBAAA,EAAA,iBAAwC;QAAxC,YAAO,GAAP,OAAO,CAAiC;IAAG,CAAC;IAEhE,qCAAU,GAAV,UAAW,OAAyC,EAAE,EAAyB;QAC3E,EAAE,CAAC,CAAC,OAAO,EAAE,KAAK,UAAU,IAAI,IAAI,CAAC,OAAO,YAAY,uBAAU,CAAC,CAAC,CAAC;YACjE,IAAI,CAAC,OAAO,CAAC,QAAQ,GAAG,EAAE,CAAC;QAC/B,CAAC;QACD,EAAE,CAAC,CAAC,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC;YAC9B,IAAM,iBAAiB,gBAChB,gBAAgB,CAAC,eAAe,IACnC,OAAO,SAAA,EACP,KAAK,qBACL,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,GACjC,CAAC;YACF,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;QACxC,CAAC;QAAC,IAAI,CAAC,CAAC;YACJ,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,wBAAkC,CAAC,CAAC,CAAC;gBAClD,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAChC,CAAC;YAAC,IAAI,CAAC,CAAC;gBACJ,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAC9B,CAAC;QACL,CAAC;IACL,CAAC;IAED,mCAAQ,GAAR,UAAS,OAAyC,EAAE,EAAyB;QACzE,EAAE,CAAC,CAAC,OAAO,EAAE,KAAK,UAAU,IAAI,IAAI,CAAC,OAAO,YAAY,uBAAU,CAAC,CAAC,CAAC;YACjE,IAAI,CAAC,OAAO,CAAC,QAAQ,GAAG,EAAE,CAAC;QAC/B,CAAC;QACD,EAAE,CAAC,CAAC,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC;YAC9B,IAAM,iBAAiB,gBAChB,gBAAgB,CAAC,eAAe,IACnC,OAAO,SAAA,EACP,KAAK,uBACL,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,GACjC,CAAC;YACF,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAC1C,CAAC;QAAC,IAAI,CAAC,CAAC;YACJ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAChC,CAAC;IACL,CAAC;IAxDsB,kCAAiB,GAAW,oCAAoC,CAAC;IACjE,gCAAe,GAAW,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAI,IAAI,CAAC,IAAI,CAAC,qBAAO,EAAE,8BAA8B,CAAC,CAAC;IAChI,gCAAe,GAA4B;QACrD,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,IAAI;QACX,IAAI,EAAE,IAAI;QACV,MAAM,EAAE,2CAA2C;QACnD,UAAU,EAAE;YACR,QAAQ,EAAE,QAAQ;YAClB,SAAS,EAAE,SAAS;YACpB,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB;YACvC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,8BAA8B;YAChD,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,0CAA0C;YACxE,UAAU,EAAE,QAAQ;YACpB,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;SACvG;KACJ,CAAA;IAyCL,uBAAC;CAAA,AA1DD,IA0DC;AA1DY,4CAAgB","sourcesContent":["\"use strict\";\r\n\r\nimport * as path from \"path\";\r\nimport * as fs from \"fs\";\r\nimport * as DataModel from \"./DataModel\";\r\nimport { FileWriter } from \"./FileWriter\";\r\nimport { homedir } from \"./Helpers/FileHelpers\";\r\n\r\nexport class DiagnosticLogger {\r\n public static readonly DEFAULT_FILE_NAME: string = \"application-insights-extension.log\";\r\n public static readonly DEFAULT_LOG_DIR: string = process.env.APPLICATIONINSIGHTS_LOGDIR || path.join(homedir, \"LogFiles/ApplicationInsights\");\r\n public static DefaultEnvelope: DataModel.DiagnosticLog = {\r\n message: null,\r\n level: null,\r\n time: null,\r\n logger: \"applicationinsights.extension.diagnostics\",\r\n properties: {\r\n language: \"nodejs\",\r\n operation: \"Startup\",\r\n siteName: process.env.WEBSITE_SITE_NAME,\r\n ikey: process.env.APPINSIGHTS_INSTRUMENTATIONKEY,\r\n extensionVersion: process.env.ApplicationInsightsAgent_EXTENSION_VERSION,\r\n sdkVersion: \"1.8.10\",\r\n subscriptionId: process.env.WEBSITE_OWNER_NAME ? process.env.WEBSITE_OWNER_NAME.split(\"+\")[0] : null,\r\n }\r\n }\r\n\r\n constructor(private _writer: DataModel.AgentLogger = console) {}\r\n\r\n logMessage(message: DataModel.DiagnosticLog | string, cb?: (err: Error) => void) {\r\n if (typeof cb === \"function\" && this._writer instanceof FileWriter) {\r\n this._writer.callback = cb;\r\n }\r\n if (typeof message === \"string\") {\r\n const diagnosticMessage: DataModel.DiagnosticLog = {\r\n ...DiagnosticLogger.DefaultEnvelope,\r\n message,\r\n level: DataModel.SeverityLevel.INFO,\r\n time: new Date().toISOString(),\r\n };\r\n this._writer.log(diagnosticMessage);\r\n } else {\r\n if (message.level === DataModel.SeverityLevel.ERROR) {\r\n this._writer.error(message);\r\n } else {\r\n this._writer.log(message);\r\n }\r\n }\r\n }\r\n\r\n logError(message: DataModel.DiagnosticLog | string, cb?: (err: Error) => void) {\r\n if (typeof cb === \"function\" && this._writer instanceof FileWriter) {\r\n this._writer.callback = cb;\r\n }\r\n if (typeof message === \"string\") {\r\n const diagnosticMessage: DataModel.DiagnosticLog = {\r\n ...DiagnosticLogger.DefaultEnvelope,\r\n message,\r\n level: DataModel.SeverityLevel.ERROR,\r\n time: new Date().toUTCString()\r\n };\r\n this._writer.error(diagnosticMessage);\r\n } else {\r\n this._writer.error(message);\r\n }\r\n }\r\n}\r\n"]}
+27
View File
@@ -0,0 +1,27 @@
import * as DataModel from "./DataModel";
export interface FileWriterOptions {
append: boolean;
deleteOnExit: boolean;
sizeLimit: number;
renamePolicy: "rolling" | "overwrite" | "stop";
chmod: number;
}
export declare const homedir: any;
export declare class FileWriter implements DataModel.AgentLogger {
private _filepath;
private _filename;
callback: (_err: Error) => void;
private _ready;
private _options;
private static _fullpathsToDelete;
private static _listenerAttached;
private static DEFAULT_OPTIONS;
static isNodeVersionCompatible(): boolean;
constructor(_filepath: string, _filename: string, options?: Partial<FileWriterOptions>);
log(message: any): void;
error(message: any): void;
private _appendFile(message);
private _writeFile(message);
private static _addCloseHandler();
private _shouldRenameFile(callback?);
}
+136
View File
@@ -0,0 +1,136 @@
"use strict";
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
var path = require("path");
var fs = require("fs");
var FileHelpers = require("./Helpers/FileHelpers");
exports.homedir = FileHelpers.homedir;
var FileWriter = (function () {
// leave at "keep at single file only", "write up to certain size limit", "clear old file on process startup"
function FileWriter(_filepath, _filename, options) {
this._filepath = _filepath;
this._filename = _filename;
this.callback = function (_err) { }; // no-op
this._ready = false;
this._options = __assign({}, FileWriter.DEFAULT_OPTIONS, options);
this._ready = FileWriter.isNodeVersionCompatible() && FileHelpers.makeStatusDirs(this._filepath);
if (this._options.deleteOnExit) {
FileWriter._addCloseHandler();
FileWriter._fullpathsToDelete.push(path.join(this._filepath, this._filename));
}
}
FileWriter.isNodeVersionCompatible = function () {
var majVer = process.versions.node.split(".")[0];
return parseInt(majVer) >= 1;
};
FileWriter.prototype.log = function (message) {
var _this = this;
if (this._ready) {
var data_1 = typeof message === "object"
? JSON.stringify(message)
: message.toString();
// Check if existing file needs to be renamed
this._shouldRenameFile(function (err, shouldRename) {
if (err)
return;
if (shouldRename) {
if (_this._options.renamePolicy === "rolling") {
FileHelpers.renameCurrentFile(_this._filepath, _this._filename, function (renameErr, renamedFullpath) {
if (renameErr)
return;
FileWriter._fullpathsToDelete.push(renamedFullpath);
_this._options.append
? _this._appendFile(data_1 + "\n")
: _this._writeFile(data_1);
});
}
else if (_this._options.renamePolicy === "overwrite") {
// Clear the current file
_this._writeFile(data_1);
}
else if (_this._options.renamePolicy === "stop") {
// Stop future logging
_this._ready = false;
}
}
else {
_this._options.append
? _this._appendFile(data_1 + "\n")
: _this._writeFile(data_1);
}
});
}
};
FileWriter.prototype.error = function (message) {
this.log(message);
};
FileWriter.prototype._appendFile = function (message) {
var _this = this;
var fullpath = path.join(this._filepath, this._filename);
fs.appendFile(fullpath, message, function (err) {
_this.callback(err);
});
};
FileWriter.prototype._writeFile = function (message) {
var fullpath = path.join(this._filepath, this._filename);
fs.writeFile(fullpath, message, { mode: this._options.chmod }, this.callback);
};
FileWriter._addCloseHandler = function () {
if (!FileWriter._listenerAttached) {
process.on("exit", function () {
FileWriter._fullpathsToDelete.forEach(function (filename) {
try {
fs.unlinkSync(filename);
}
catch (err) { }
});
});
FileWriter._listenerAttached = true;
}
};
FileWriter.prototype._shouldRenameFile = function (callback) {
var _this = this;
var fullpath = path.join(this._filepath, this._filename);
fs.stat(fullpath, function (err, stats) {
if (err) {
if (err.code === "ENOENT" && typeof callback === "function") {
callback(null, false);
}
else if (typeof callback === "function") {
callback(err);
}
return;
}
if (stats.size > _this._options.sizeLimit) {
callback(null, true);
}
else {
var createDate = new Date(stats.birthtime);
var currentDate = new Date();
var result = (createDate.getUTCDate() !== currentDate.getUTCDate() ||
createDate.getUTCMonth() !== currentDate.getUTCMonth() ||
createDate.getUTCFullYear() !== currentDate.getUTCFullYear());
callback(null, result);
}
});
};
FileWriter._fullpathsToDelete = [];
FileWriter._listenerAttached = false;
FileWriter.DEFAULT_OPTIONS = {
append: false,
deleteOnExit: true,
sizeLimit: 10 * 1024,
renamePolicy: "stop",
chmod: 420 // rw/r/r
};
return FileWriter;
}());
exports.FileWriter = FileWriter;
//# sourceMappingURL=FileWriter.js.map
File diff suppressed because one or more lines are too long
+2
View File
@@ -0,0 +1,2 @@
import { DiagnosticLogger } from "./DiagnosticLogger";
export declare function sdkAlreadyExists(_logger: DiagnosticLogger): boolean;
+32
View File
@@ -0,0 +1,32 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function sdkAlreadyExists(_logger) {
try {
// appInstance should either resolve to user SDK or crash. If it resolves to attach SDK, user probably modified their NODE_PATH
var appInstance = void 0;
try {
// Node 8.9+
appInstance = require.resolve("applicationinsights", { paths: [process.cwd()] });
}
catch (e) {
// Node <8.9
appInstance = require.resolve(process.cwd() + "/node_modules/applicationinsights");
}
// If loaded instance is in Azure machine home path do not attach the SDK, this means customer already instrumented their app
if (appInstance.indexOf("home") > -1) {
_logger.logMessage("applicationinsights module is already installed in this application; not re-attaching. Installed SDK location: " +
appInstance);
return true;
}
else {
// ApplicationInsights could be loaded outside of customer application, attach in this case
return false;
}
}
catch (e) {
// crashed while trying to resolve "applicationinsights", so SDK does not exist. Attach appinsights
return false;
}
}
exports.sdkAlreadyExists = sdkAlreadyExists;
//# sourceMappingURL=Helpers.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"Helpers.js","sourceRoot":"","sources":["../../Bootstrap/Helpers.ts"],"names":[],"mappings":";;AAEA,0BAAiC,OAAyB;IACtD,IAAI,CAAC;QACD,+HAA+H;QAC/H,IAAI,WAAW,SAAQ,CAAC;QACxB,IAAI,CAAC;YACD,YAAY;YACZ,WAAW,GAAI,OAAO,CAAC,OAAe,CAAC,qBAAqB,EAAE,EAAE,KAAK,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QAC9F,CAAC;QAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACT,YAAY;YACZ,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,mCAAmC,CAAC,CAAC;QACvF,CAAC;QACD,6HAA6H;QAC7H,EAAE,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACnC,OAAO,CAAC,UAAU,CACd,iHAAiH;gBACjH,WAAW,CACd,CAAC;YACF,MAAM,CAAC,IAAI,CAAC;QAChB,CAAC;QACD,IAAI,CAAC,CAAC;YACF,2FAA2F;YAC3F,MAAM,CAAC,KAAK,CAAC;QACjB,CAAC;IACL,CAAC;IAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACT,mGAAmG;QACnG,MAAM,CAAC,KAAK,CAAC;IACjB,CAAC;AACL,CAAC;AA3BD,4CA2BC","sourcesContent":["import { DiagnosticLogger } from \"./DiagnosticLogger\";\r\n\r\nexport function sdkAlreadyExists(_logger: DiagnosticLogger): boolean {\r\n try {\r\n // appInstance should either resolve to user SDK or crash. If it resolves to attach SDK, user probably modified their NODE_PATH\r\n let appInstance: string;\r\n try {\r\n // Node 8.9+\r\n appInstance = (require.resolve as any)(\"applicationinsights\", { paths: [process.cwd()] });\r\n } catch (e) {\r\n // Node <8.9\r\n appInstance = require.resolve(process.cwd() + \"/node_modules/applicationinsights\");\r\n }\r\n // If loaded instance is in Azure machine home path do not attach the SDK, this means customer already instrumented their app\r\n if (appInstance.indexOf(\"home\") > -1) {\r\n _logger.logMessage(\r\n \"applicationinsights module is already installed in this application; not re-attaching. Installed SDK location: \" +\r\n appInstance\r\n );\r\n return true;\r\n }\r\n else {\r\n // ApplicationInsights could be loaded outside of customer application, attach in this case\r\n return false;\r\n }\r\n } catch (e) {\r\n // crashed while trying to resolve \"applicationinsights\", so SDK does not exist. Attach appinsights\r\n return false;\r\n }\r\n}\r\n"]}
@@ -0,0 +1,3 @@
export declare const homedir: any;
export declare function makeStatusDirs(filepath: string): boolean;
export declare function renameCurrentFile(filepath: string, filename: string, callback?: (err: Error | null, destfullpath?: string) => void): void;
+70
View File
@@ -0,0 +1,70 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var path = require("path");
var fs = require("fs");
var os = require("os");
exports.homedir = os.homedir ? os.homedir() : (process.env[(process.platform == "win32") ? "USERPROFILE" : "HOME"]);
/**
* Zero dependencies: recursive mkdir
*/
function mkDirByPathSync(HOME_DIR, targetDir, _a) {
var _b = (_a === void 0 ? {} : _a).isRelativeToScript, isRelativeToScript = _b === void 0 ? false : _b;
var sep = path.sep;
var initDir = path.isAbsolute(targetDir) ? sep : "";
var baseDir = isRelativeToScript ? __dirname : ".";
return targetDir.split(sep).reduce(function (parentDir, childDir) {
var curDir = path.resolve(baseDir, parentDir, childDir);
try {
// Don't try to recreate homedir
if (HOME_DIR.indexOf(curDir) === -1) {
fs.mkdirSync(curDir);
}
}
catch (err) {
if (err.code === "EEXIST") {
return curDir;
}
// To avoid `EISDIR` error on Mac and `EACCES`-->`ENOENT` and `EPERM` on Windows.
if (err.code === "ENOENT") {
throw new Error("EACCES: permission denied, mkdir \"" + parentDir + "\"");
}
var caughtErr = ["EACCES", "EPERM", "EISDIR"].indexOf(err.code) > -1;
if (!caughtErr || caughtErr && curDir === path.resolve(targetDir)) {
throw err; // Throw if it's just the last created dir.
}
}
return curDir;
}, initDir);
}
function makeStatusDirs(filepath) {
try {
mkDirByPathSync(exports.homedir, filepath.replace(/\\/g, path.sep).replace(/\//g, path.sep));
return true;
}
catch (e) {
console.error("Error creating Application Insights status folder", e);
return false;
}
}
exports.makeStatusDirs = makeStatusDirs;
function renameCurrentFile(filepath, filename, callback) {
var fullpath = path.join(filepath, filename);
var basename = path.basename(filename, path.extname(filename));
var stats = fs.stat(fullpath, function (statsErr, stats) {
if (statsErr) {
return callback(statsErr);
}
var createDate = new Date(stats.birthtime);
var destfilename = basename + "-" +
createDate.toISOString().replace(/[T:\.]/g, "_").replace("Z", "") +
path.extname(filename) + ".old";
var destfullpath = path.join(filepath, destfilename);
fs.rename(fullpath, destfullpath, function (renameErr) {
if (typeof callback === "function") {
callback(renameErr, destfullpath);
}
});
});
}
exports.renameCurrentFile = renameCurrentFile;
//# sourceMappingURL=FileHelpers.js.map
File diff suppressed because one or more lines are too long
+5
View File
@@ -0,0 +1,5 @@
import * as DataModel from "./DataModel";
export declare class NoopLogger implements DataModel.AgentLogger {
log(message?: any, ...optional: any[]): void;
error(message?: any, ...optional: any[]): void;
}
+21
View File
@@ -0,0 +1,21 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var NoopLogger = (function () {
function NoopLogger() {
}
NoopLogger.prototype.log = function (message) {
var optional = [];
for (var _i = 1; _i < arguments.length; _i++) {
optional[_i - 1] = arguments[_i];
}
};
NoopLogger.prototype.error = function (message) {
var optional = [];
for (var _i = 1; _i < arguments.length; _i++) {
optional[_i - 1] = arguments[_i];
}
};
return NoopLogger;
}());
exports.NoopLogger = NoopLogger;
//# sourceMappingURL=NoopLogger.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"NoopLogger.js","sourceRoot":"","sources":["../../Bootstrap/NoopLogger.ts"],"names":[],"mappings":";;AAGA;IAAA;IAKA,CAAC;IAJG,wBAAG,GAAH,UAAI,OAAa;QAAE,kBAAkB;aAAlB,UAAkB,EAAlB,qBAAkB,EAAlB,IAAkB;YAAlB,iCAAkB;;IACrC,CAAC;IACD,0BAAK,GAAL,UAAM,OAAa;QAAE,kBAAkB;aAAlB,UAAkB,EAAlB,qBAAkB,EAAlB,IAAkB;YAAlB,iCAAkB;;IACvC,CAAC;IACL,iBAAC;AAAD,CAAC,AALD,IAKC;AALY,gCAAU","sourcesContent":["import * as DataModel from \"./DataModel\";\r\nimport { FileWriter } from \"./FileWriter\";\r\n\r\nexport class NoopLogger implements DataModel.AgentLogger {\r\n log(message?: any, ...optional: any[]): void {\r\n }\r\n error(message?: any, ...optional: any[]): void {\r\n }\r\n}\r\n"]}
+3
View File
@@ -0,0 +1,3 @@
import * as types from "../applicationinsights";
declare var appInsights: typeof types;
export = appInsights;
+14
View File
@@ -0,0 +1,14 @@
"use strict";
var StatusLogger_1 = require("./StatusLogger");
var DiagnosticLogger_1 = require("./DiagnosticLogger");
var NoopLogger_1 = require("./NoopLogger");
var appInsightsLoader = require("./Default");
appInsightsLoader.setUsagePrefix("alr_"); // App Services Linux Attach
// Set Status.json logger
appInsightsLoader.setStatusLogger(new StatusLogger_1.StatusLogger(new NoopLogger_1.NoopLogger()));
// Set Attach Diagnostic Logger
appInsightsLoader.setLogger(new DiagnosticLogger_1.DiagnosticLogger(new NoopLogger_1.NoopLogger()));
// Start the SDK
var appInsights = appInsightsLoader.setupAndStart();
module.exports = appInsights;
//# sourceMappingURL=Oryx.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"Oryx.js","sourceRoot":"","sources":["../../Bootstrap/Oryx.ts"],"names":[],"mappings":";AACA,+CAA8C;AAC9C,uDAAsD;AACtD,2CAA0C;AAC1C,6CAAgD;AAEhD,iBAAiB,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,4BAA4B;AAEtE,yBAAyB;AACzB,iBAAiB,CAAC,eAAe,CAAC,IAAI,2BAAY,CAAC,IAAI,uBAAU,EAAE,CAAC,CAAC,CAAC;AAEtE,+BAA+B;AAC/B,iBAAiB,CAAC,SAAS,CAAC,IAAI,mCAAgB,CAAC,IAAI,uBAAU,EAAE,CAAC,CAAC,CAAC;AAEpE,gBAAgB;AAChB,IAAI,WAAW,GAAG,iBAAiB,CAAC,aAAa,EAAE,CAAC;AAEpD,iBAAS,WAAW,CAAC","sourcesContent":["import * as types from \"../applicationinsights\"; // needed but unused\r\nimport { StatusLogger } from \"./StatusLogger\";\r\nimport { DiagnosticLogger } from \"./DiagnosticLogger\";\r\nimport { NoopLogger } from \"./NoopLogger\";\r\nimport appInsightsLoader = require(\"./Default\");\r\n\r\nappInsightsLoader.setUsagePrefix(\"alr_\"); // App Services Linux Attach\r\n\r\n// Set Status.json logger\r\nappInsightsLoader.setStatusLogger(new StatusLogger(new NoopLogger()));\r\n\r\n// Set Attach Diagnostic Logger\r\nappInsightsLoader.setLogger(new DiagnosticLogger(new NoopLogger()));\r\n\r\n// Start the SDK\r\nvar appInsights = appInsightsLoader.setupAndStart();\r\n\r\nexport = appInsights;\r\n"]}
+19
View File
@@ -0,0 +1,19 @@
import * as DataModel from "./DataModel";
export interface StatusContract {
AgentInitializedSuccessfully: boolean;
Reason?: string;
SDKPresent: boolean;
AppType: string;
MachineName: string;
PID: string;
SdkVersion: string;
Ikey: string;
}
export declare class StatusLogger {
_writer: DataModel.AgentLogger;
static readonly DEFAULT_FILE_PATH: string;
static readonly DEFAULT_FILE_NAME: string;
static readonly DEFAULT_STATUS: StatusContract;
constructor(_writer?: DataModel.AgentLogger);
logStatus(data: StatusContract, cb?: (err: Error) => void): void;
}
+43
View File
@@ -0,0 +1,43 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var os = require("os");
var path = require("path");
var fs = require("fs");
var FileWriter_1 = require("./FileWriter");
function readPackageVersion() {
var packageJsonPath = path.resolve(__dirname, "../../package.json");
try {
var packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
if (packageJson && typeof packageJson.version === "string") {
return packageJson.version;
}
}
catch (e) { }
return "unknown";
}
var StatusLogger = (function () {
function StatusLogger(_writer) {
if (_writer === void 0) { _writer = console; }
this._writer = _writer;
}
StatusLogger.prototype.logStatus = function (data, cb) {
if (typeof cb === "function" && this._writer instanceof FileWriter_1.FileWriter) {
this._writer.callback = cb;
}
this._writer.log(data);
};
StatusLogger.DEFAULT_FILE_PATH = path.join(FileWriter_1.homedir, "status");
StatusLogger.DEFAULT_FILE_NAME = "status_" + os.hostname() + "_" + process.pid + ".json";
StatusLogger.DEFAULT_STATUS = {
AgentInitializedSuccessfully: false,
SDKPresent: false,
Ikey: "unknown",
AppType: "node.js",
SdkVersion: readPackageVersion(),
MachineName: os.hostname(),
PID: String(process.pid)
};
return StatusLogger;
}());
exports.StatusLogger = StatusLogger;
//# sourceMappingURL=StatusLogger.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"StatusLogger.js","sourceRoot":"","sources":["../../Bootstrap/StatusLogger.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,uBAAyB;AACzB,2BAA6B;AAC7B,uBAAyB;AAEzB,2CAAmD;AAanD;IACI,IAAI,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;IACpE,IAAI,CAAC;QACD,IAAI,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;QACvE,EAAE,CAAC,CAAC,WAAW,IAAI,OAAO,WAAW,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC;YACzD,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC;QAC/B,CAAC;IACL,CAAC;IAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACf,MAAM,CAAC,SAAS,CAAC;AACrB,CAAC;AAED;IAaI,sBAAmB,OAAwC;QAAxC,wBAAA,EAAA,iBAAwC;QAAxC,YAAO,GAAP,OAAO,CAAiC;IAAG,CAAC;IAExD,gCAAS,GAAhB,UAAiB,IAAoB,EAAE,EAAyB;QAC5D,EAAE,CAAC,CAAC,OAAO,EAAE,KAAK,UAAU,IAAI,IAAI,CAAC,OAAO,YAAY,uBAAU,CAAC,CAAC,CAAC;YACjE,IAAI,CAAC,OAAO,CAAC,QAAQ,GAAG,EAAE,CAAC;QAC/B,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAnBsB,8BAAiB,GAAW,IAAI,CAAC,IAAI,CAAC,oBAAO,EAAE,QAAQ,CAAC,CAAC;IACzD,8BAAiB,GAAW,YAAU,EAAE,CAAC,QAAQ,EAAE,SAAI,OAAO,CAAC,GAAG,UAAO,CAAC;IAC1E,2BAAc,GAAmB;QACpD,4BAA4B,EAAE,KAAK;QACnC,UAAU,EAAE,KAAK;QACjB,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,SAAS;QAClB,UAAU,EAAE,kBAAkB,EAAE;QAChC,WAAW,EAAE,EAAE,CAAC,QAAQ,EAAE;QAC1B,GAAG,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC;KAC3B,CAAA;IAUL,mBAAC;CAAA,AArBD,IAqBC;AArBY,oCAAY","sourcesContent":["\"use strict\";\r\n\r\nimport * as os from \"os\";\r\nimport * as path from \"path\";\r\nimport * as fs from \"fs\";\r\nimport * as DataModel from \"./DataModel\";\r\nimport { FileWriter, homedir } from \"./FileWriter\";\r\n\r\nexport interface StatusContract {\r\n AgentInitializedSuccessfully: boolean;\r\n Reason?: string;\r\n SDKPresent: boolean;\r\n AppType: string;\r\n MachineName: string;\r\n PID: string;\r\n SdkVersion: string;\r\n Ikey: string;\r\n}\r\n\r\nfunction readPackageVersion() {\r\n let packageJsonPath = path.resolve(__dirname, \"../../package.json\");\r\n try {\r\n let packageJson = JSON.parse(fs.readFileSync(packageJsonPath, \"utf8\"));\r\n if (packageJson && typeof packageJson.version === \"string\") {\r\n return packageJson.version;\r\n }\r\n } catch (e) { }\r\n return \"unknown\";\r\n}\r\n\r\nexport class StatusLogger {\r\n public static readonly DEFAULT_FILE_PATH: string = path.join(homedir, \"status\");\r\n public static readonly DEFAULT_FILE_NAME: string = `status_${os.hostname()}_${process.pid}.json`;\r\n public static readonly DEFAULT_STATUS: StatusContract = {\r\n AgentInitializedSuccessfully: false,\r\n SDKPresent: false,\r\n Ikey: \"unknown\",\r\n AppType: \"node.js\",\r\n SdkVersion: readPackageVersion(),\r\n MachineName: os.hostname(),\r\n PID: String(process.pid)\r\n }\r\n\r\n constructor(public _writer: DataModel.AgentLogger = console) {}\r\n\r\n public logStatus(data: StatusContract, cb?: (err: Error) => void) {\r\n if (typeof cb === \"function\" && this._writer instanceof FileWriter) {\r\n this._writer.callback = cb;\r\n }\r\n this._writer.log(data);\r\n }\r\n}\r\n"]}
+59
View File
@@ -0,0 +1,59 @@
import Contracts = require("./Contracts");
export declare const DEFAULT_BREEZE_ENDPOINT = "https://dc.services.visualstudio.com";
export declare const DEFAULT_LIVEMETRICS_ENDPOINT = "https://rt.services.visualstudio.com";
export declare const DEFAULT_LIVEMETRICS_HOST = "rt.services.visualstudio.com";
export declare enum QuickPulseCounter {
COMMITTED_BYTES = "\\Memory\\Committed Bytes",
PROCESSOR_TIME = "\\Processor(_Total)\\% Processor Time",
REQUEST_RATE = "\\ApplicationInsights\\Requests/Sec",
REQUEST_FAILURE_RATE = "\\ApplicationInsights\\Requests Failed/Sec",
REQUEST_DURATION = "\\ApplicationInsights\\Request Duration",
DEPENDENCY_RATE = "\\ApplicationInsights\\Dependency Calls/Sec",
DEPENDENCY_FAILURE_RATE = "\\ApplicationInsights\\Dependency Calls Failed/Sec",
DEPENDENCY_DURATION = "\\ApplicationInsights\\Dependency Call Duration",
EXCEPTION_RATE = "\\ApplicationInsights\\Exceptions/Sec",
}
export declare enum PerformanceCounter {
PRIVATE_BYTES = "\\Process(??APP_WIN32_PROC??)\\Private Bytes",
AVAILABLE_BYTES = "\\Memory\\Available Bytes",
PROCESSOR_TIME = "\\Processor(_Total)\\% Processor Time",
PROCESS_TIME = "\\Process(??APP_WIN32_PROC??)\\% Processor Time",
REQUEST_RATE = "\\ASP.NET Applications(??APP_W3SVC_PROC??)\\Requests/Sec",
REQUEST_DURATION = "\\ASP.NET Applications(??APP_W3SVC_PROC??)\\Request Execution Time",
}
/**
* Map a PerformanceCounter/QuickPulseCounter to a QuickPulseCounter. If no mapping exists, mapping is *undefined*
*/
export declare const PerformanceToQuickPulseCounter: {
[key: string]: QuickPulseCounter;
};
export declare type QuickPulseDocumentType = "Event" | "Exception" | "Trace" | "Metric" | "Request" | "RemoteDependency" | "Availability" | "PageView";
export declare type QuickPulseType = "EventTelemetryDocument" | "ExceptionTelemetryDocument" | "TraceTelemetryDocument" | "MetricTelemetryDocument" | "RequestTelemetryDocument" | "DependencyTelemetryDocument" | "AvailabilityTelemetryDocument" | "PageViewTelemetryDocument";
export declare const QuickPulseDocumentType: {
[key in Contracts.TelemetryTypeKeys]: QuickPulseDocumentType;
};
export declare const QuickPulseType: {
[key in Contracts.TelemetryTypeKeys]: QuickPulseType;
};
export declare const TelemetryTypeStringToQuickPulseType: {
[key in Contracts.TelemetryTypeValues]: QuickPulseType;
};
export declare const TelemetryTypeStringToQuickPulseDocumentType: {
[key in Contracts.TelemetryTypeValues]: QuickPulseDocumentType;
};
export declare const SpanAttribute: {
HttpHost: string;
HttpMethod: string;
HttpPort: string;
HttpStatusCode: string;
HttpUrl: string;
HttpUserAgent: string;
GrpcMethod: string;
GrpcService: string;
};
export declare const DependencyTypeName: {
Grpc: string;
Http: string;
InProc: string;
};
export declare const HeartBeatMetricName = "HeartBeat";

Some files were not shown because too many files have changed in this diff Show More