Skip to content

Add Logs to the JavaScript SDK #15526

New issue

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

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

Already on GitHub? Sign in to your account

Closed
7 tasks done
AbhiPrasad opened this issue Feb 27, 2025 · 2 comments
Closed
7 tasks done

Add Logs to the JavaScript SDK #15526

AbhiPrasad opened this issue Feb 27, 2025 · 2 comments
Assignees

Comments

@AbhiPrasad
Copy link
Member

AbhiPrasad commented Feb 27, 2025

In #15442 we created an experimental logging API to test out the new logging product.

Based on the experimental API, we devised unified public API we'd like all SDKs to implement: https://www.notion.so/sentry/Logs-in-the-SDK-1a48b10e4b5d80b1827fe14d9fd0236b#1a48b10e4b5d80a782a9efc6fd463acf

This task looks at implementing this logging API in the JavaScript SDKs

@AbhiPrasad
Copy link
Member Author

After chatting with the team, we decided to go for an approach that does not add a new method to the client. This saves on bundle size, but does add some complexity around how internals and managed and exposed.

You can see both attempts here:

  1. Adding method to client: feat(core): Add client.captureLog method #15715
  2. Adding standalone captureLog: feat(core): Add captureLog method #15717

Pros and cons:

Pros Cons
Client Method
  • Logic is better encapsulated
  • Matches other SDK implementations
  • Easy access to client.flush()
  • More easy for child classes (browser, server-runtime) to override functionality
  • Bundle Size increase of 1%-3% (!!!)
  • Hard to change public API/method name without more bundle size cost
Standalone Method
  • Low bundle size hit
  • Easier to rename or deprecate API
  • Need to expose internal methods to access log buffer data structure
  • Don't match with other SDKs

AbhiPrasad added a commit that referenced this issue Mar 21, 2025
ref #15526

Continuing off the work from
#15717, this PR adds
the logging public API to the Browser SDK. It also adds a basic flushing
strategy to the SDK that is timeout based. This is done to help save
bundle size.

The main file added was `log.ts`. This has three areas to look at:

1. The logger methods for `trace`, `debug`, `info`, `warn`, `error`,
`fatal` (the log severity levels) as well as an internal capture log
helper all these methods call.
2. `addFlushingListeners` which adds listeners to flush the logs buffer
on client flush and document visibility hidden.
3. a flush timeout that flushes logs after X seconds, which gets
restarted when new logs are captured.

I also removed any logs logic from the `BrowserClient`, which should
ensure this stays as bundle size efficient as possible.

Usage:

```js
import * as Sentry from "@sentry/browser";

Sentry.init({
  dsn: "your-dsn-here",
  _experiments: {
    enableLogs: true  // This is required to use the logging features
  }
});

// Trace level (lowest severity)
Sentry.logger.trace("This is a trace message", { userId: 123 });

// Debug level
Sentry.logger.debug("This is a debug message", { component: "UserProfile" });

// Info level
Sentry.logger.info("User logged in successfully", { userId: 123 });

// Warning level
Sentry.logger.warn("API response was slow", { responseTime: 2500 });

// Error level
Sentry.logger.error("Failed to load user data", { userId: 123, errorCode: 404 });

// Critical level
Sentry.logger.critical("Database connection failed", { dbHost: "primary-db" });

// Fatal level (highest severity)
Sentry.logger.fatal("Application is shutting down unexpectedly", { memory: "exhausted" });
```
AbhiPrasad added a commit that referenced this issue Mar 24, 2025
ref #15526

Continuing off the work from
#15763, this PR adds
the logging public API to the Node SDK. It also adds a basic
weight-based flushing strategy to the SDK that is in the server-runtime
client.

The main file added was `log.ts`. In that file I've added logger methods
for `trace`, `debug`, `info`, `warn`, `error`, `fatal` (the log severity
levels) as well as an internal capture log helper all these methods
call.

Usage:

```js
import * as Sentry from "@sentry/node";

Sentry.init({
  dsn: "your-dsn-here",
  _experiments: {
    enableLogs: true  // This is required to use the logging features
  }
});

// Trace level (lowest severity)
Sentry.logger.trace("This is a trace message", { userId: 123 });

// Debug level
Sentry.logger.debug("This is a debug message", { component: "UserProfile" });

// Info level
Sentry.logger.info("User %s logged in successfully", [123]);

// Warning level
Sentry.logger.warn("API response was slow", { responseTime: 2500 });

// Error level
Sentry.logger.error("Failed to load user %s data", [123], { errorCode: 404 });

// Critical level
Sentry.logger.critical("Database connection failed", { dbHost: "primary-db" });

// Fatal level (highest severity)
Sentry.logger.fatal("Application is shutting down unexpectedly", { memory: "exhausted" });
```
AbhiPrasad added a commit that referenced this issue Mar 25, 2025
ref #15526

Adds support for `beforeSendLog`, currently in the `_experiments`
options namespace.

While adding `beforeSendLog`, I noticed the `beforeCaptureLog` was not
placed correctly. This PR also fixes that, and introduces a
`afterCaptureLog` that runs in the capturing lifecycle properly.
AbhiPrasad added a commit that referenced this issue Mar 25, 2025
ref #15526

This adds support for parameterizing logs via the existing
`ParameterizedString` type and `parameterize` function exported from the
SDK. This works for all usages of the logger, so browser and Node.js.

Usage:

```js
Sentry.logger.info(Sentry.logger.fmt`User ${user} updated profile picture`, {
  userId: 'user-123',
  imageSize: '2.5MB',
  timestamp: Date.now()
});
```

`fmt` is an alias to `Sentry.parameterize` that is exported from the
`logger` namespace.

To support this change, I changed the typing of `ParameterizedString` to
accept `unknown[]` for `__sentry_template_values__`. This is broadening
the type, so should not be a breaking change.
[`logentry.params`](https://github.com./getsentry/relay/blob/a91f0c92860f88789ad6092ef5b1062aa3e34b80/relay-event-schema/src/protocol/logentry.rs#L51C27-L51C32)
should accept all kinds of values, relay handles formatting them
correctly.
@AbhiPrasad
Copy link
Member Author

I know we got #15815 left, but this is ready to release now :)

Just tested everything on some demo app and it all works! Closing as such.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant