Skip to content

Commit

Permalink
Console instrumentation: send a Faro error for console.error logs (#703)
Browse files Browse the repository at this point in the history
  • Loading branch information
codecapitano authored Oct 11, 2024
1 parent bc7e264 commit a43406f
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 34 deletions.
57 changes: 30 additions & 27 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,34 @@

## Next

- Improvement (`@grafana/faro-web-sdk`): The console instrumentation now sends an `Error` signal
instead of a `Log` signal for `console.error()` calls (#703).

## 1.10.2

- Fix (`@grafana/faro-web-tracing`): Enhance the xhr instrumentation to handle both URL objects and
strings seamlessly (#695).

## 1.10.1

- Enhancement (`@grafana/faro-web-sdk`): Isolated Faro instances now exclude the default collector
- Improvement (`@grafana/faro-web-sdk`): Isolated Faro instances now exclude the default collector
URLs of other instances by default (#684).
- Enhancement (`@grafana/faro-web-sdk`): The `pushError` API now automatically includes `error.cause`
- Improvement (`@grafana/faro-web-sdk`): The `pushError` API now automatically includes `error.cause`
in the Faro exception context (#688).

- Fix (`@grafana/faro-transport-otlp-http [experimental]`): add `service.namespace` attribute if set
(#687).

### Breaking

- Change (`@grafana/faro-transport-otlp-http [experimental]`): update semantic attributes
- Improvement (`@grafana/faro-transport-otlp-http [experimental]`): update semantic attributes
for browser (#684).
- `browser.user_agent` is replaced by `user_agent.original`
- `browser.os` is replaced by `browser.platform`

## 1.10.0

- Change (`@grafana/faro-web-sdk`): don't automatically send a `view_change` event for the default
- Improvement (`@grafana/faro-web-sdk`): don't automatically send a `view_change` event for the default
view (#647)

- Dependencies (`@grafana/faro-web-tracing`): upgrade otel deps (#670)
Expand Down Expand Up @@ -55,24 +58,24 @@

## 1.9.0

- Enhancement (`@grafana/faro-web-sdk`): Provide and option to pass a correction timestamp via the
- Improvement (`@grafana/faro-web-sdk`): Provide and option to pass a correction timestamp via the
Faro API (#658).

- Fix (`@grafana/faro-web-sdk`): Adjust the timestamp of a navigation or resource event to reflect
the actual time the event occurred, rather than the signal creation time. (#658).

- Change: (`@grafana/faro-web-tracing`) The underlying XHR and Fetch instrumentation are now
- Improvement: (`@grafana/faro-web-tracing`) The underlying XHR and Fetch instrumentation are now
configured to ignore network events by default. This behavior can be enabled back through the
options in the WebTracing class.

## 1.8.2

- Enhancement (`@grafana/faro-web-tracing`): ensure that span status is always set to error for
- Improvement (`@grafana/faro-web-tracing`): ensure that span status is always set to error for
erroneous xhr requests (#644).

## 1.8.1

- Enhancement (`@grafana/faro-web-tracing`): ensure that span status is always set to error for
- Improvement (`@grafana/faro-web-tracing`): ensure that span status is always set to error for
erroneous fetch requests (#641).

## 1.8.0
Expand All @@ -81,9 +84,9 @@
- Feature (`@grafana/faro-web-sdk`): set span context for navigation events (#608).
- Feature (`@grafana/faro-react`): add helper functions to initialize React Router integration (#622).

- Enhancement (`@grafana/faro-web-sdk`): Auto extend a session if the Faro receiver indicates that a
- Improvement (`@grafana/faro-web-sdk`): Auto extend a session if the Faro receiver indicates that a
session is invalid (#591).
- Enhancement (`@grafana/faro-web-tracing`): provide the `app.namespace` attribute in the app meta
- Improvement (`@grafana/faro-web-tracing`): provide the `app.namespace` attribute in the app meta
which is attached as `service.namespace` to the resource attributes object (#627).

- Dependencies (`@grafana/faro-web-tracing`): upgrade otel deps (#621).
Expand All @@ -106,32 +109,32 @@

## 1.7.1

- Enhancement (`@grafana/faro-core`): Config has now a parameter `logArgsSerializer` to set a custom serializer for
- Improvement (`@grafana/faro-core`): Config has now a parameter `logArgsSerializer` to set a custom serializer for
log arguments (#564). This is useful if log message args are complex and might produce `[object Object]` in the logs.
- Fix (`@grafana/faro-web-tracing`): Fix an import issue causing builds to fail (#581).
- Fix (`@grafana/faro-react`): Fix type issues in react data route wrapper `withFaroRouterInstrumentation` (#584).

## 1.7.0

- Enhancement (`@grafana/faro-web-sdk`): provide option to globally
- Improvement (`@grafana/faro-web-sdk`): provide option to globally
exclude endpoint URLs from being tracked. This applies to the following instrumentations:
performance, xhr, fetch and web-tracing (#554).
- Update (`faro demo`): Update Demo to pin docker images and replace Cortex by Mimir (#563).
- Enhancement (`faro demo`): Migrate demo Grafana agent to Grafana alloy
- Improvement (`faro demo`): Migrate demo Grafana agent to Grafana alloy

## 1.6.0

- Docs(`@grafana/faro-web-sdk`, `@grafana/faro-web-tracing`): Remove pre-release warning (#550).
- Change (`@grafana/faro-web-tracing`): Remove redundant DocumentLoadInstrumentation.
- Improvement (`@grafana/faro-web-tracing`): Remove redundant DocumentLoadInstrumentation.
Faro tracks page load data by default (#551).
- Change(`@grafana/faro-web-sdk`): Performance instrumentation only tracks resource entries initiated
- Improvement(`@grafana/faro-web-sdk`): Performance instrumentation only tracks resource entries initiated
by calls to the `fetch` method or `xhr-html requests`. To track all resource entries set
`trackResources: true` (#560).

## 1.5.1

- Feature(`@grafana/faro-web-sdk`): Add parsing time to FaroNavigationTiming (#541).
- Change ()(`@grafana/faro-web-sdk`): Get rid of structureClone. It caused breakage in some
- Improvement ()(`@grafana/faro-web-sdk`): Get rid of structureClone. It caused breakage in some
sandboxed environments because of injected proxy objects (#536).
- Feat(`@grafana/faro-web-sdk`): Add K6 test ID to K6 meta if available in window.k6 object (#531).

Expand All @@ -152,16 +155,16 @@

## 1.4.1

- Enhancement (`@grafana/faro-web-tracing`): Dedupe Faro trace events (#507).
- Improvement (`@grafana/faro-web-tracing`): Dedupe Faro trace events (#507).

## 1.4.0

- Feat (`@grafana/faro-web-sdk`): Enable Faro Navigation and Resource timings instrumentation by default (#482).
- Enhancement (`@grafana/faro-web-tracing`): Send a dedicated Faro event for traces of kind=client (#499).
- Improvement (`@grafana/faro-web-tracing`): Send a dedicated Faro event for traces of kind=client (#499).

## 1.3.9

- Enhancement (`@grafana/faro-web-sdk`): add `duration` property in `faro.performance.resource` timings and
- Improvement (`@grafana/faro-web-sdk`): add `duration` property in `faro.performance.resource` timings and
rename property `totalNavigationTime` to `duration` in `faro.performance.navigation` timings (#490).
- Fix (`@grafana/faro-web-sdk`): crash when navigator.userAgentData is undefined (#494).

Expand All @@ -171,17 +174,17 @@

## 1.3.7

- Enhancement (`@grafana/faro-web-sdk`): add response time to performance timings (#465).
- Improvement (`@grafana/faro-web-sdk`): add response time to performance timings (#465).
- Deps (`@grafana/faro-web-tracing`): Update `instrumentation-document-load` which prevents build.
from breaking (#467).

## 1.3.6

- Feature preview (`@grafana/faro-web-sdk`): instrument navigation and resource timings. As long as
this feature is in preview it is disabled by default (#434)
- Enhancement (`@grafana/faro-web-tracing`): Automatically add the value of the MetaApp environment
- Improvement (`@grafana/faro-web-tracing`): Automatically add the value of the MetaApp environment
property to the resource attributes `deployment.environment` property (#453)
- Change (`@grafana/faro-web-sdk`): change storage key prefix for Faro session to use reverse domain
- Improvement (`@grafana/faro-web-sdk`): change storage key prefix for Faro session to use reverse domain
notation (#432)
- Fix (`@grafana/faro-core`): make check for presence of Event more robust (#436)

Expand Down Expand Up @@ -229,16 +232,16 @@
- Deps: upgrade OTEL dependencies, remove outdated resolutions (#391).
- Fix (Web Tracing): send otel timings, like timeUnixNano, as string instead in LongBits format (#391).
- Feat: session based sampling (#385).
- Change: Send better attributes with the view and route transition events to contain information about
- Improvement: Send better attributes with the view and route transition events to contain information about
the previous route or view (`from*`) and the destination route or view (`to*`) (#397).
- Breaking❗️: React Instrumentation, the route transition event is renamed from `routeChange` to
`route_change`. The `url` and `route` attributes sent with the event are renamed to `toRoute` and
`toUrl`.(#397).

## 1.2.8

- Change: Custom x-faro-session-id header will now be added to legacy sessions as well (#384).
- Change: Lower maxSessionPersistenceTime for tracked sessions and export tooling to make it easier
- Improvement: Custom x-faro-session-id header will now be added to legacy sessions as well (#384).
- Improvement: Lower maxSessionPersistenceTime for tracked sessions and export tooling to make it easier
to manually remove a persisted session (#387)

## 1.2.7
Expand All @@ -249,8 +252,8 @@

- Feat: Add x-faro-session header to identify client session id to server
for fetch and xhr instrumentations (#377)
- Change (): Always send x-faro-session-id header, independent of the chosen session management (#381).
- Change: If new session management is used, send dedicated session lifecycle events to reflect if a
- Improvement (): Always send x-faro-session-id header, independent of the chosen session management (#381).
- Improvement: If new session management is used, send dedicated session lifecycle events to reflect if a
new session is started, a session is resume or extended (#380)

## 1.2.5
Expand Down
15 changes: 10 additions & 5 deletions cypress/e2e/demo/logs.cy.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { LogEvent, LogLevel } from '@grafana/faro-core';
import { ExceptionEvent, LogEvent, LogLevel } from '@grafana/faro-core';

context('Logs', () => {
context('Console logs', () => {
[LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR].forEach((level) => {
it(`will capture ${level} level`, () => {
cy.interceptCollector((body) => {
const item = body.logs?.find(
(item: LogEvent) => item?.level === level && item?.message === `This is a console ${level} message`
);
let item =
level === 'error'
? body.exceptions?.find((item: ExceptionEvent) => item?.value === `This is a console ${level} message`)
: body.logs?.find(
(item: LogEvent) => item?.level === level && item?.message === `This is a console ${level} message`
);

console.log('item :>> ', item);

return item != null ? 'log' : undefined;
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { ExceptionEvent, initializeFaro, TransportItem } from '@grafana/faro-core';
import { mockConfig, MockTransport } from '@grafana/faro-core/src/testUtils';

import { makeCoreConfig } from '../../config';

import { ConsoleInstrumentation } from './instrumentation';

describe('ConsoleInstrumentation', () => {
afterEach(() => {
jest.resetAllMocks();
jest.restoreAllMocks();
});

it('send a faro error when console.error is called', () => {
const mockTransport = new MockTransport();

initializeFaro(
makeCoreConfig(
mockConfig({
transports: [mockTransport],
instrumentations: [new ConsoleInstrumentation()],
unpatchedConsole: {
error: jest.fn(),
} as unknown as Console,
})
)!
);

console.error('console.error no 1');
console.error('with object', { foo: 'bar', baz: 'bam' });

expect(mockTransport.items).toHaveLength(2);

expect((mockTransport.items[0] as TransportItem<ExceptionEvent>)?.payload.type).toBe('Error');
expect((mockTransport.items[0] as TransportItem<ExceptionEvent>)?.payload.value).toBe('console.error no 1');
expect((mockTransport.items[1] as TransportItem<ExceptionEvent>)?.payload.type).toBe('Error');
expect((mockTransport.items[1] as TransportItem<ExceptionEvent>)?.payload.value).toBe(
'with object {"foo":"bar","baz":"bam"}'
);
});
});
10 changes: 8 additions & 2 deletions packages/web-sdk/src/instrumentations/console/instrumentation.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { allLogLevels, BaseInstrumentation, LogLevel, VERSION } from '@grafana/faro-core';
import { allLogLevels, BaseInstrumentation, isArray, isObject, LogLevel, VERSION } from '@grafana/faro-core';

import type { ConsoleInstrumentationOptions } from './types';

Expand All @@ -21,7 +21,13 @@ export class ConsoleInstrumentation extends BaseInstrumentation {
/* eslint-disable-next-line no-console */
console[level] = (...args) => {
try {
this.api.pushLog(args, { level });
if (level === LogLevel.ERROR) {
this.api.pushError(
new Error(args.map((arg) => (isObject(arg) || isArray(arg) ? JSON.stringify(arg) : arg)).join(' '))
);
} else {
this.api.pushLog(args, { level });
}
} catch (err) {
this.logError(err);
} finally {
Expand Down

0 comments on commit a43406f

Please sign in to comment.