Skip to content

Commit

Permalink
track function defaults to tracking trace
Browse files Browse the repository at this point in the history
and exception
  • Loading branch information
paed01 committed Nov 13, 2023
1 parent 05adc05 commit 5a4eb4b
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 18 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ jobs:
timeout-minutes: 20
strategy:
matrix:
node-version: [ 18, 20, latest ]
node-version: [ 16, 18, 20, latest ]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- run: npm i
- run: npm i --loglevel=error
- run: npm run build
- run: npm run test:lcov
- name: Coveralls
Expand Down
31 changes: 27 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@

Forward pino logger to Application Insights.

Ships with [fake applicationinsights](#class-fakeapplicationinsightssetupstring) helper test class.

## Usage

```js
import { pino } from 'pino';
import compose from '@zerodep/pino-applicationinsights';
import compose from '@0dep/pino-applicationinsights';

const transport = compose({
track(chunk) {
Expand All @@ -23,18 +25,39 @@ const transport = compose({
const logger = pino({ level: 'trace' }, transport);
```

or as multi transport:

```js
import { pino } from 'pino';

const transport = pino.transport({
targets: {
level: 'info',
target: '@0dep/pino-applicationinsights',
options: {
connectionString: process.env.APPLICATIONINSIGHTS_CONNECTION_STRING,
config: {
disableStatsbeat: true,
},
},
},
});

const logger = pino(transport);
```

## API

### `compose(opts[, TelemetryTransformation]) => Stream`

Build transport stream function.

- `opts`:
* `track(chunk)`: track function called with Telemetry client context
- `chunk`: [Telemetry:ish](#telemetrish-object) object
* `connectionString`: Application Insights connection string or instrumentation key
* `track(chunk)`: optional track function called with Telemetry client context, defaults to tracking trace and exception
- `chunk`: [Telemetry:ish](#telemetrish-object) object
* `config`: optional Application Insights Telemetry client config
* `destination`: optional destination stream, makes build ignore the above options
* `destination`: optional destination stream, makes compose ignore the above options
* `ignoreKeys`: optional pino ignore keys, used to filter telemetry properties, defaults to `['hostname', 'pid', 'level', 'time', 'msg']`
- `TelemetryTransformation`: optional transformation stream extending [TelemetryTransformation](#class-telemetrytransformationoptions-config)

Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@
},
"keywords": [
"pino",
"transport",
"applicationinsights",
"application",
"insights",
"transport",
"fake",
"mock"
],
Expand All @@ -56,7 +58,6 @@
"@types/mocha": "^10.0.3",
"@types/node": "^16.18.60",
"applicationinsights": "^2.9.0",
"applicationinsights-opentelemetry": "npm:applicationinsights@^3.0.0-beta.10",
"c8": "^8.0.1",
"chai": "^4.3.10",
"chronokinesis": "^6.0.0",
Expand Down
20 changes: 17 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ export class TelemetryTransformation extends Transform {
* @returns {ReturnType<typeof import('pino-abstract-transport')>}
*/
export default function compose(opts, Transformation = TelemetryTransformation) {
if (!opts.destination && (!opts.track || !opts.connectionString)) {
const track = opts.track ?? trackTraceAndException;
if (!opts.destination && (typeof track !== 'function' || !opts.connectionString)) {
throw new TypeError('track function and connectionString are required');
}

Expand All @@ -131,12 +132,12 @@ export default function compose(opts, Transformation = TelemetryTransformation)
Object.assign(client.config, opts.config);
}

const track = opts.track.bind(client);
const trackTelemetry = track.bind(client);
destination = new Writable({
objectMode: true,
autoDestroy: true,
write(chunk, _encoding, callback) {
track(chunk);
trackTelemetry(chunk);
callback();
},
});
Expand All @@ -148,3 +149,16 @@ export default function compose(opts, Transformation = TelemetryTransformation)
return promises.pipeline(source, transformToTelemetry, destination);
});
}

/**
* Default track function
*
* Tracks trace and occasional exception
* @param {import('../types/interfaces.js').LogTelemetry} chunk
* @this {import('applicationinsights').TelemetryClient}
*/
export function trackTraceAndException(chunk) {
const { time, severity, msg: message, properties, exception } = chunk;
this.trackTrace({ time, severity, message, properties });
if (exception) this.trackException({ time, severity, exception });
}
30 changes: 29 additions & 1 deletion test/src/compose-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,18 @@ describe('compose', () => {
}).to.throw(TypeError, /connectionString/);
});

it('with connection string but without track throws', () => {
it('with track function but without connection string throws', () => {
expect(() => {
compose({ track() {} });
}).to.throw(TypeError, /connectionString/);
});

it('with connection string and non-function track throws', () => {
expect(() => {
compose({ track: {} });
}).to.throw(TypeError, /connectionString/);
});

it('with destination not a Writable stream throws', () => {
expect(() => {
compose({ destination: {} });
Expand Down Expand Up @@ -244,5 +250,27 @@ describe('compose', () => {

transport.destroy();
});

it('defaults to tracking trace and exception', async () => {
const expectMessage = fakeAI.expectMessageData();
const expectException = fakeAI.expectExceptionData();

const transport = compose({
connectionString,
config: { maxBatchSize: 1, disableStatsbeat: true },
});

const logger = pino({ level: 'trace' }, transport);

logger.error(new Error('bar'), 'foo');

const msg = await expectMessage;

expect(msg.body.data).to.have.property('baseType', 'MessageData');

const err = await expectException;

expect(err.body.data).to.have.property('baseType', 'ExceptionData');
});
});
});
5 changes: 0 additions & 5 deletions test/src/log-transport-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,6 @@ describe('log transport', () => {
fakeAI = new FakeApplicationInsights(connectionString);

transport = compose({
track(chunk) {
const { time, severity, msg: message, properties, exception } = chunk;
this.trackTrace({ time, severity, message, properties });
if (exception) this.trackException({ time, exception, severity });
},
connectionString,
config: { maxBatchSize: 1, disableStatsbeat: true },
});
Expand Down
8 changes: 7 additions & 1 deletion types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
declare module '@0dep/pino-applicationinsights' {
import type { TelemetryClient, Contracts } from 'applicationinsights';
import type { Transform } from 'node:stream';
import type { Writable } from 'stream';
import type { TelemetryClient, Contracts } from 'applicationinsights';
/// <reference types="node" />
/**
* Compose Application Insights pino transport
* @param opts - transport options
* @param Transformation - optional Telemetry transformation stream
* */
export default function compose(opts: ConnectionStringComposeConfig | DestinationComposeConfig, Transformation?: typeof TelemetryTransformation | undefined): ReturnType<typeof import('pino-abstract-transport')>;
/**
* Default track function
*
* Tracks trace and occasional exception
* */
export function trackTraceAndException(this: TelemetryClient, chunk: LogTelemetry): void;
/**
* Telemetry exception
*
Expand Down

0 comments on commit 5a4eb4b

Please sign in to comment.