---
title: "What to Log"
description: "Practical guidance on what to log, how to search logs, and when to set alerts."
url: https://docs.sentry.io/guides/logs/
---

# What to Log

You've set up [Sentry Logs](https://docs.sentry.io/product/explore/logs.md). Now what?

This guide covers the high-value logging patterns that help you debug faster and catch problems before users report them.

## [Anatomy of a Log](https://docs.sentry.io/guides/logs.md#anatomy-of-a-log)

Every structured log follows the same format:

**JavaScript**

```javascript
Sentry.logger.<level>(message, { attributes });
```

**Python**

```python
sentry_sdk.logger.<level>(message, attribute=value)
```

**PHP**

```php
\Sentry\logger()-><level>(message, attributes: [...]);
```

**.NET**

```csharp
using Sentry;
SentrySdk.Logger.<Level>(message);
```

Logs in Sentry are automatically trace-connected. Each log shows a trace ID that links to the full [trace view](https://docs.sentry.io/concepts/key-terms/tracing.md#traces-to-trace-view).

**Ruby**

```ruby
Sentry.logger.<level>(message)
```

**Flutter**

```dart
import 'package:sentry/sentry.dart';
Sentry.logger.<level>(message);
```

**Swift**

```swift
import Sentry
SentrySDK.logger.<level>(message, attributes: [...])
```

**Kotlin**

```kotlin
import io.sentry.Sentry
Sentry.logger().<level>(message)
```

**Levels:** `trace`, `debug`, `info`, `warn` (or `warning` in Python), `error`, `fatal`

**Attributes:** Key-value pairs you can search and filter on. Consistency matters, so use whatever naming convention fits your codebase.

**JavaScript**

```javascript
Sentry.logger.info("Order completed", {
  orderId: "order_123",
  userId: user.id,
  amount: 149.99,
  paymentMethod: "stripe",
});
```

**Python**

```python
sentry_sdk.logger.info("Order completed",
    order_id="order_123",
    user_id=user.id,
    amount=149.99,
    payment_method="stripe"
)
```

**PHP**

```php
\Sentry\logger()->info('Order completed', attributes: [
    'order_id' => 'order_123',
    'user_id' => $user->id,
    'amount' => 149.99,
    'payment_method' => 'stripe',
]);
```

**.NET**

```csharp
using Sentry;

SentrySdk.Logger.Info("Order completed", logger => logger
    .SetAttribute("orderId", "order_123")
    .SetAttribute("userId", user.Id)
    .SetAttribute("amount", 149.99)
    .SetAttribute("paymentMethod", "stripe"));
```

**Ruby**

```ruby
Sentry.logger.info('Order completed',
  order_id: 'order_123',
  user_id: user.id,
  amount: 149.99,
  payment_method: 'stripe'
)
```

**Flutter**

```dart
Sentry.logger.info('Order completed', attributes: {
  'orderId': 'order_123',
  'userId': user.id,
  'amount': 149.99,
  'paymentMethod': 'stripe',
});
```

**Swift**

```swift
import Sentry

SentrySDK.logger.info("Order completed", attributes: [
    "orderId": "order_123",
    "userId": user.id,
    "amount": 149.99,
    "paymentMethod": "stripe"
])
```

**Kotlin**

```kotlin
import io.sentry.Sentry

Sentry.logger().info("Order completed orderId=%s userId=%s amount=%.2f",
    "order_123", user.id, 149.99)
```

Logs in Sentry are automatically trace-connected. Each log shows a trace ID that links to the full [trace view](https://docs.sentry.io/concepts/key-terms/tracing/trace-view.md).

## [Where to Add Logs](https://docs.sentry.io/guides/logs.md#where-to-add-logs)

Start with these five areas and you'll catch most issues before users do.

### [1. Authentication Events](https://docs.sentry.io/guides/logs.md#1-authentication-events)

Login flows are invisible until something breaks. Log successes and failures to spot patterns like brute force attempts, OAuth misconfigurations, or MFA issues.

**JavaScript**

```javascript
// After successful authentication
Sentry.logger.info("User logged in", {
  userId: user.id,
  authMethod: "oauth",
  provider: "google",
});

// After authentication fails
Sentry.logger.warn("Login failed", {
  email: maskedEmail,
  reason: "invalid_password",
  attemptCount: 3,
});
```

**Python**

```python
import sentry_sdk

# After successful authentication
sentry_sdk.logger.info("User logged in",
    user_id=user.id,
    auth_method="oauth",
    provider="google"
)

# After authentication fails
sentry_sdk.logger.warning("Login failed",
    email=masked_email,
    reason="invalid_password",
    attempt_count=3
)
```

**PHP**

```php
// After successful authentication
\Sentry\logger()->info('User logged in', attributes: [
    'user_id' => $user->id,
    'auth_method' => 'oauth',
    'provider' => 'google',
]);

// After authentication fails
\Sentry\logger()->warn('Login failed', attributes: [
    'email' => $maskedEmail,
    'reason' => 'invalid_password',
    'attempt_count' => 3,
]);
```

**.NET**

```csharp
// After successful authentication
SentrySdk.Logger.Info("User logged in", logger => logger
    .SetAttribute("userId", user.Id)
    .SetAttribute("authMethod", "oauth")
    .SetAttribute("provider", "google"));

// After authentication fails
SentrySdk.Logger.Warning("Login failed", logger => logger
    .SetAttribute("email", maskedEmail)
    .SetAttribute("reason", "invalid_password")
    .SetAttribute("attemptCount", 3));
```

**Ruby**

```ruby
# After successful authentication
Sentry.logger.info('User logged in',
  user_id: user.id,
  auth_method: 'oauth',
  provider: 'google'
)

# After authentication fails
Sentry.logger.warn('Login failed',
  email: masked_email,
  reason: 'invalid_password',
  attempt_count: 3
)
```

**Flutter**

```dart
// After successful authentication
Sentry.logger.info('User logged in', attributes: {
  'userId': user.id,
  'authMethod': 'oauth',
  'provider': 'google',
});

// After authentication fails
Sentry.logger.warn('Login failed', attributes: {
  'email': maskedEmail,
  'reason': 'invalid_password',
  'attemptCount': 3,
});
```

**Swift**

```swift
import Sentry

// After successful authentication
SentrySDK.logger.info("User logged in", attributes: [
    "userId": user.id,
    "authMethod": "oauth",
    "provider": "google"
])

// After authentication fails
SentrySDK.logger.warn("Login failed", attributes: [
    "email": maskedEmail,
    "reason": "invalid_password",
    "attemptCount": 3
])
```

**Kotlin**

```kotlin
import io.sentry.Sentry

// After successful authentication
Sentry.logger().info("User logged in userId=%s authMethod=%s", user.id, "oauth")

// After authentication fails
Sentry.logger().warn("Login failed email=%s reason=%s", maskedEmail, "invalid_password")
```

**Query in [Explore > Logs](https://sentry.io/orgredirect/organizations/:orgslug/explore/logs/):** `userId:123 "logged in"` or `severity:warn authMethod:*`

**Alert idea:** Alert when `severity:warn "Login failed"` spikes in a 5-minute window—this can indicate brute force attempts or auth provider issues.

### [2. Payment and Checkout](https://docs.sentry.io/guides/logs.md#2-payment-and-checkout)

Money paths need visibility even when they succeed. When payments fail, you need context fast.

**JavaScript**

```javascript
// After payment gateway returns an error
Sentry.logger.error("Payment failed", {
  orderId: "order_123",
  amount: 99.99,
  gateway: "stripe",
  errorCode: "card_declined",
  cartItems: 3,
});
```

**Python**

```python
import sentry_sdk

sentry_sdk.init(...)

# After payment gateway returns an error
sentry_sdk.logger.error("Payment failed",
    order_id="order_123",
    amount=99.99,
    gateway="stripe",
    error_code="card_declined",
    cart_items=3
)
```

**PHP**

```php
// After payment gateway returns an error
\Sentry\logger()->error('Payment failed', attributes: [
    'order_id' => 'order_123',
    'amount' => 99.99,
    'gateway' => 'stripe',
    'error_code' => 'card_declined',
    'cart_items' => 3,
]);
```

**.NET**

```csharp
// After payment gateway returns an error
SentrySdk.Logger.Error("Payment failed", logger => logger
    .SetAttribute("orderId", "order_123")
    .SetAttribute("amount", 99.99)
    .SetAttribute("gateway", "stripe")
    .SetAttribute("errorCode", "card_declined")
    .SetAttribute("cartItems", 3));
```

**Ruby**

```ruby
# After payment gateway returns an error
Sentry.logger.error('Payment failed',
  order_id: 'order_123',
  amount: 99.99,
  gateway: 'stripe',
  error_code: 'card_declined',
  cart_items: 3
)
```

**Flutter**

```dart
// After payment gateway returns an error
Sentry.logger.error('Payment failed', attributes: {
  'orderId': 'order_123',
  'amount': 99.99,
  'gateway': 'stripe',
  'errorCode': 'card_declined',
  'cartItems': 3,
});
```

**Swift**

```swift
import Sentry

// After payment gateway returns an error
SentrySDK.logger.error("Payment failed", attributes: [
    "orderId": "order_123",
    "amount": 99.99,
    "gateway": "stripe",
    "errorCode": "card_declined",
    "cartItems": 3
])
```

**Kotlin**

```kotlin
import io.sentry.Sentry

// After payment gateway returns an error
Sentry.logger().error("Payment failed orderId=%s gateway=%s errorCode=%s",
    "order_123", "stripe", "card_declined")
```

**Query in [Explore > Logs](https://sentry.io/orgredirect/organizations/:orgslug/explore/logs/):** `orderId:order_123` or `severity:error gateway:stripe`

**Alert idea:** Alert when `severity:error gateway:*` spikes—this can indicate payment provider outages.

### [3. External APIs and Async Operations](https://docs.sentry.io/guides/logs.md#3-external-apis-and-async-operations)

Traces capture what your code does. Logs capture context about external triggers and async boundaries. These are things like webhooks, scheduled tasks, and third-party API responses that traces can't automatically instrument.

**JavaScript**

```javascript
// Third-party API call
const start = Date.now();
const response = await shippingApi.getRates(items);

Sentry.logger.info("Shipping rates fetched", {
  service: "shipping-provider",
  endpoint: "/rates",
  durationMs: Date.now() - start,
  rateCount: response.rates.length,
});

// Webhook received
Sentry.logger.info("Webhook received", {
  source: "stripe",
  eventType: "payment_intent.succeeded",
  paymentId: event.data.object.id,
});
```

**Python**

```python
import time
import sentry_sdk

sentry_sdk.init(...)

# Third-party API call
start = time.time()
response = shipping_api.get_rates(items)

sentry_sdk.logger.info("Shipping rates fetched",
    service="shipping-provider",
    endpoint="/rates",
    duration_ms=int((time.time() - start) * 1000),
    rate_count=len(response.rates)
)

# Webhook received
sentry_sdk.logger.info("Webhook received",
    source="stripe",
    event_type="payment_intent.succeeded",
    payment_id=event["data"]["object"]["id"]
)
```

**PHP**

```php
// Third-party API call
$start = microtime(true);
$response = $shippingApi->getRates($items);

\Sentry\logger()->info('Shipping rates fetched', attributes: [
    'service' => 'shipping-provider',
    'endpoint' => '/rates',
    'duration_ms' => (int)((microtime(true) - $start) * 1000),
    'rate_count' => count($response->rates),
]);

// Webhook received
\Sentry\logger()->info('Webhook received', attributes: [
    'source' => 'stripe',
    'event_type' => 'payment_intent.succeeded',
    'payment_id' => $event['data']['object']['id'],
]);
```

**.NET**

```csharp
// Third-party API call
var stopwatch = Stopwatch.StartNew();
var response = await shippingApi.GetRatesAsync(items);

SentrySdk.Logger.Info("Shipping rates fetched", logger => logger
    .SetAttribute("service", "shipping-provider")
    .SetAttribute("endpoint", "/rates")
    .SetAttribute("durationMs", stopwatch.ElapsedMilliseconds)
    .SetAttribute("rateCount", response.Rates.Count));

// Webhook received
SentrySdk.Logger.Info("Webhook received", logger => logger
    .SetAttribute("source", "stripe")
    .SetAttribute("eventType", "payment_intent.succeeded")
    .SetAttribute("paymentId", eventData.Object.Id));
```

**Ruby**

```ruby
# Third-party API call
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
response = shipping_api.get_rates(items)

Sentry.logger.info('Shipping rates fetched',
  service: 'shipping-provider',
  endpoint: '/rates',
  duration_ms: ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - start) * 1000).to_i,
  rate_count: response.rates.length
)

# Webhook received
Sentry.logger.info('Webhook received',
  source: 'stripe',
  event_type: 'payment_intent.succeeded',
  payment_id: event['data']['object']['id']
)
```

**Flutter**

```dart
// Third-party API call
final stopwatch = Stopwatch()..start();
final response = await shippingApi.getRates(items);

Sentry.logger.info('Shipping rates fetched', attributes: {
  'service': 'shipping-provider',
  'endpoint': '/rates',
  'durationMs': stopwatch.elapsedMilliseconds,
  'rateCount': response.rates.length,
});

// Webhook received
Sentry.logger.info('Webhook received', attributes: {
  'source': 'stripe',
  'eventType': 'payment_intent.succeeded',
  'paymentId': event.data.object.id,
});
```

**Swift**

```swift
import Sentry

// Third-party API call
let start = Date()
let response = try await shippingApi.getRates(items)

SentrySDK.logger.info("Shipping rates fetched", attributes: [
    "service": "shipping-provider",
    "endpoint": "/rates",
    "durationMs": Int(Date().timeIntervalSince(start) * 1000),
    "rateCount": response.rates.count
])

// Webhook received
SentrySDK.logger.info("Webhook received", attributes: [
    "source": "stripe",
    "eventType": "payment_intent.succeeded",
    "paymentId": event.data.object.id
])
```

**Kotlin**

```kotlin
import io.sentry.Sentry

// Third-party API call
val start = System.currentTimeMillis()
val response = shippingApi.getRates(items)

Sentry.logger().info("Shipping rates fetched service=%s durationMs=%d",
    "shipping-provider", System.currentTimeMillis() - start)

// Webhook received
Sentry.logger().info("Webhook received source=%s eventType=%s",
    "stripe", "payment_intent.succeeded")
```

**Query in [Explore > Logs](https://sentry.io/orgredirect/organizations/:orgslug/explore/logs/):** `service:shipping-provider durationMs:>2000` or `source:stripe`

**Alert idea:** Alert when `service:* durationMs:>3000` to catch third-party slowdowns before they cascade.

### [4. Background Jobs](https://docs.sentry.io/guides/logs.md#4-background-jobs)

Jobs run outside the request context. Without logs, failed jobs are invisible until someone notices missing data.

**JavaScript**

```javascript
// Inside background job handler
Sentry.logger.info("Job started", {
  jobType: "email-digest",
  jobId: "job_456",
  queue: "notifications",
});

Sentry.logger.error("Job failed", {
  jobType: "email-digest",
  jobId: "job_456",
  retryCount: 3,
  lastError: "SMTP timeout",
});
```

**Python**

```python
import sentry_sdk

sentry_sdk.init(...)

# Inside background job handler
sentry_sdk.logger.info("Job started",
    job_type="email-digest",
    job_id="job_456",
    queue="notifications"
)

sentry_sdk.logger.error("Job failed",
    job_type="email-digest",
    job_id="job_456",
    retry_count=3,
    last_error="SMTP timeout"
)
```

**PHP**

```php
// Inside background job handler
\Sentry\logger()->info('Job started', attributes: [
    'job_type' => 'email-digest',
    'job_id' => 'job_456',
    'queue' => 'notifications',
]);

\Sentry\logger()->error('Job failed', attributes: [
    'job_type' => 'email-digest',
    'job_id' => 'job_456',
    'retry_count' => 3,
    'last_error' => 'SMTP timeout',
]);
```

**.NET**

```csharp
// Inside background job handler
SentrySdk.Logger.Info("Job started", logger => logger
    .SetAttribute("jobType", "email-digest")
    .SetAttribute("jobId", "job_456")
    .SetAttribute("queue", "notifications"));

SentrySdk.Logger.Error("Job failed", logger => logger
    .SetAttribute("jobType", "email-digest")
    .SetAttribute("jobId", "job_456")
    .SetAttribute("retryCount", 3)
    .SetAttribute("lastError", "SMTP timeout"));
```

**Ruby**

```ruby
# Inside background job handler
Sentry.logger.info('Job started',
  job_type: 'email-digest',
  job_id: 'job_456',
  queue: 'notifications'
)

Sentry.logger.error('Job failed',
  job_type: 'email-digest',
  job_id: 'job_456',
  retry_count: 3,
  last_error: 'SMTP timeout'
)
```

**Flutter**

```dart
// Inside background job handler
Sentry.logger.info('Job started', attributes: {
  'jobType': 'email-digest',
  'jobId': 'job_456',
  'queue': 'notifications',
});

Sentry.logger.error('Job failed', attributes: {
  'jobType': 'email-digest',
  'jobId': 'job_456',
  'retryCount': 3,
  'lastError': 'SMTP timeout',
});
```

**Swift**

```swift
import Sentry

// Inside background job handler
SentrySDK.logger.info("Job started", attributes: [
    "jobType": "email-digest",
    "jobId": "job_456",
    "queue": "notifications"
])

SentrySDK.logger.error("Job failed", attributes: [
    "jobType": "email-digest",
    "jobId": "job_456",
    "retryCount": 3,
    "lastError": "SMTP timeout"
])
```

**Kotlin**

```kotlin
import io.sentry.Sentry

// Inside background job handler
Sentry.logger().info("Job started jobType=%s jobId=%s queue=%s",
    "email-digest", "job_456", "notifications")

Sentry.logger().error("Job failed jobType=%s jobId=%s retryCount=%d",
    "email-digest", "job_456", 3)
```

**Query in [Explore > Logs](https://sentry.io/orgredirect/organizations/:orgslug/explore/logs/):** `jobType:email-digest severity:error`

**Alert idea:** Alert when `severity:error jobType:*` spikes—this can indicate queue processing issues or downstream failures.

### [5. Feature Flags and Config Changes](https://docs.sentry.io/guides/logs.md#5-feature-flags-and-config-changes)

When something breaks after a deploy, the first question is "what changed?" Logging flag evaluations and config reloads gives you that answer instantly.

**JavaScript**

```javascript
// When feature flag is checked or config changes
Sentry.logger.info("Feature flag evaluated", {
  flag: "new-checkout-flow",
  enabled: true,
  userId: user.id,
});

Sentry.logger.warn("Config reloaded", {
  reason: "env-change",
  changedKeys: ["API_TIMEOUT", "MAX_CONNECTIONS"],
});
```

**Python**

```python
import sentry_sdk

sentry_sdk.init(...)

# When feature flag is checked or config changes
sentry_sdk.logger.info("Feature flag evaluated",
    flag="new-checkout-flow",
    enabled=True,
    user_id=user.id
)

sentry_sdk.logger.warning("Config reloaded",
    reason="env-change",
    changed_keys=["API_TIMEOUT", "MAX_CONNECTIONS"]
)
```

**PHP**

```php
// When feature flag is checked or config changes
\Sentry\logger()->info('Feature flag evaluated', attributes: [
    'flag' => 'new-checkout-flow',
    'enabled' => true,
    'user_id' => $user->id,
]);

\Sentry\logger()->warn('Config reloaded', attributes: [
    'reason' => 'env-change',
    'changed_keys' => ['API_TIMEOUT', 'MAX_CONNECTIONS'],
]);
```

**.NET**

```csharp
// When feature flag is checked or config changes
SentrySdk.Logger.Info("Feature flag evaluated", logger => logger
    .SetAttribute("flag", "new-checkout-flow")
    .SetAttribute("enabled", true)
    .SetAttribute("userId", user.Id));

SentrySdk.Logger.Warning("Config reloaded", logger => logger
    .SetAttribute("reason", "env-change")
    .SetAttribute("changedKeys", new[] { "API_TIMEOUT", "MAX_CONNECTIONS" }));
```

**Ruby**

```ruby
# When feature flag is checked or config changes
Sentry.logger.info('Feature flag evaluated',
  flag: 'new-checkout-flow',
  enabled: true,
  user_id: user.id
)

Sentry.logger.warn('Config reloaded',
  reason: 'env-change',
  changed_keys: ['API_TIMEOUT', 'MAX_CONNECTIONS']
)
```

**Flutter**

```dart
// When feature flag is checked or config changes
Sentry.logger.info('Feature flag evaluated', attributes: {
  'flag': 'new-checkout-flow',
  'enabled': true,
  'userId': user.id,
});

Sentry.logger.warn('Config reloaded', attributes: {
  'reason': 'env-change',
  'changedKeys': ['API_TIMEOUT', 'MAX_CONNECTIONS'],
});
```

**Swift**

```swift
import Sentry

// When feature flag is checked or config changes
SentrySDK.logger.info("Feature flag evaluated", attributes: [
    "flag": "new-checkout-flow",
    "enabled": true,
    "userId": user.id
])

SentrySDK.logger.warn("Config reloaded", attributes: [
    "reason": "env-change",
    "changedKeys": ["API_TIMEOUT", "MAX_CONNECTIONS"]
])
```

**Kotlin**

```kotlin
import io.sentry.Sentry

// When feature flag is checked or config changes
Sentry.logger().info("Feature flag evaluated flag=%s enabled=%b userId=%s",
    "new-checkout-flow", true, user.id)

Sentry.logger().warn("Config reloaded reason=%s", "env-change")
```

**Query in [Explore > Logs](https://sentry.io/orgredirect/organizations/:orgslug/explore/logs/):** `flag:new-checkout-flow` or `"Config reloaded"`

## [Creating Alerts From Logs](https://docs.sentry.io/guides/logs.md#creating-alerts-from-logs)

1. Go to **Explore > Logs**

2. Enter your search query (e.g., `severity:error gateway:*`)

3. Click **Save As** - **Alert**

4. Choose a threshold type:

   * **Static:** Alert when count exceeds a value
   * **Percent Change:** Alert when count changes relative to a previous period
   * **Anomaly:** Let Sentry detect unusual patterns

5. Configure notification channels and save

Learn about [creating alerts](https://docs.sentry.io/product/monitors-and-alerts/alerts.md) and [notifications](https://docs.sentry.io/product/notifications.md).

## [Logging Strategy](https://docs.sentry.io/guides/logs.md#logging-strategy)

### [Development Logging](https://docs.sentry.io/guides/logs.md#development-logging)

In development, set sample rates to 100% to catch everything. This helps you understand what logs are being generated and tune your instrumentation before it hits production.

**Development configuration:**

**JavaScript**

```javascript
Sentry.init({
  dsn: "...",
  environment: "development",
  tracesSampleRate: 1.0, // 100% of traces
  // Capture all logs in development
  integrations: [
    Sentry.captureConsoleIntegration({
      levels: ["log", "info", "warn", "error", "debug"],
    }),
  ],
});
```

**Python**

```python
import sentry_sdk

sentry_sdk.init(
    dsn="...",
    environment="development",
    traces_sample_rate=1.0,  # 100% of traces
    enable_logs=True,
)
```

**PHP**

```php
\Sentry\init([
    'dsn' => '...',
    'environment' => 'development',
    'traces_sample_rate' => 1.0,  // 100% of traces
    'enable_logs' => true,
]);
```

**.NET**

```csharp
SentrySdk.Init(options =>
{
    options.Dsn = "...";
    options.Environment = "development";
    options.TracesSampleRate = 1.0;  // 100% of traces
    options.EnableLogs = true;
});
```

**Ruby**

```ruby
Sentry.init do |config|
  config.dsn = '...'
  config.environment = 'development'
  config.traces_sample_rate = 1.0  # 100% of traces
  config.enable_logs = true
end
```

**Flutter**

```dart
await SentryFlutter.init(
  (options) {
    options.dsn = '...';
    options.environment = 'development';
    options.tracesSampleRate = 1.0;  // 100% of traces
    options.enableLogs = true;
  },
  appRunner: () => runApp(MyApp()),
);
```

**Swift**

```swift
import Sentry

SentrySDK.start { options in
    options.dsn = "..."
    options.environment = "development"
    options.tracesSampleRate = 1.0  // 100% of traces
    options.enableLogs = true
}
```

**Kotlin**

```kotlin
import io.sentry.android.core.SentryAndroid

SentryAndroid.init(context) { options ->
    options.dsn = "..."
    options.environment = "development"
    options.tracesSampleRate = 1.0  // 100% of traces
    options.logs.enabled = true
}
```

Use verbose logging levels like `debug` (development diagnostics) and `trace` (fine-grained execution details) freely in development. You can filter these out in production using [beforeSendLog](https://docs.sentry.io/platform-redirect.md?next=%2Fconfiguration%2Foptions%2F%23beforeSendLog) to only capture `info` and above.

### [Production Logging](https://docs.sentry.io/guides/logs.md#production-logging)

Local debugging often means many small logs tracing execution flow. In production, this creates noise that's hard to query.

Instead, log fewer messages with higher cardinality. Store events during execution and emit them as a single structured log.

**Don't do this:**

**JavaScript**

```javascript
Sentry.logger.info("Checkout started", { userId: "882" });
Sentry.logger.info("Discount applied", { code: "WINTER20" });
Sentry.logger.error("Payment failed", { reason: "Insufficient Funds" });
```

**Python**

```python
sentry_sdk.logger.info("Checkout started", user_id="882")
sentry_sdk.logger.info("Discount applied", code="WINTER20")
sentry_sdk.logger.error("Payment failed", reason="Insufficient Funds")
```

**PHP**

```php
\Sentry\logger()->info('Checkout started', attributes: ['user_id' => '882']);
\Sentry\logger()->info('Discount applied', attributes: ['code' => 'WINTER20']);
\Sentry\logger()->error('Payment failed', attributes: ['reason' => 'Insufficient Funds']);
```

**.NET**

```csharp
SentrySdk.Logger.Info("Checkout started", l => l.SetAttribute("userId", "882"));
SentrySdk.Logger.Info("Discount applied", l => l.SetAttribute("code", "WINTER20"));
SentrySdk.Logger.Error("Payment failed", l => l.SetAttribute("reason", "Insufficient Funds"));
```

**Ruby**

```ruby
Sentry.logger.info('Checkout started', user_id: '882')
Sentry.logger.info('Discount applied', code: 'WINTER20')
Sentry.logger.error('Payment failed', reason: 'Insufficient Funds')
```

**Flutter**

```dart
Sentry.logger.info('Checkout started', attributes: {'userId': '882'});
Sentry.logger.info('Discount applied', attributes: {'code': 'WINTER20'});
Sentry.logger.error('Payment failed', attributes: {'reason': 'Insufficient Funds'});
```

**Swift**

```swift
SentrySDK.logger.info("Checkout started", attributes: ["userId": "882"])
SentrySDK.logger.info("Discount applied", attributes: ["code": "WINTER20"])
SentrySDK.logger.error("Payment failed", attributes: ["reason": "Insufficient Funds"])
```

**Kotlin**

```kotlin
Sentry.logger().info("Checkout started userId=%s", "882")
Sentry.logger().info("Discount applied code=%s", "WINTER20")
Sentry.logger().error("Payment failed reason=%s", "Insufficient Funds")
```

These logs are trace-connected, but searching for the error won't return the userId or discount code from the same transaction.

**Do this instead:**

**JavaScript**

```javascript
Sentry.logger.error("Checkout failed", {
  userId: "882",
  orderId: "order_pc_991",
  cartTotal: 142.5,
  discountCode: "WINTER20",
  paymentMethod: "stripe",
  errorReason: "Insufficient Funds",
  itemCount: 4,
});
```

**Python**

```python
sentry_sdk.logger.error("Checkout failed",
    user_id="882",
    order_id="order_pc_991",
    cart_total=142.50,
    discount_code="WINTER20",
    payment_method="stripe",
    error_reason="Insufficient Funds",
    item_count=4
)
```

**PHP**

```php
\Sentry\logger()->error('Checkout failed', attributes: [
    'user_id' => '882',
    'order_id' => 'order_pc_991',
    'cart_total' => 142.50,
    'discount_code' => 'WINTER20',
    'payment_method' => 'stripe',
    'error_reason' => 'Insufficient Funds',
    'item_count' => 4,
]);
```

**.NET**

```csharp
SentrySdk.Logger.Error("Checkout failed", logger => logger
    .SetAttribute("userId", "882")
    .SetAttribute("orderId", "order_pc_991")
    .SetAttribute("cartTotal", 142.50)
    .SetAttribute("discountCode", "WINTER20")
    .SetAttribute("paymentMethod", "stripe")
    .SetAttribute("errorReason", "Insufficient Funds")
    .SetAttribute("itemCount", 4));
```

**Ruby**

```ruby
Sentry.logger.error('Checkout failed',
  user_id: '882',
  order_id: 'order_pc_991',
  cart_total: 142.50,
  discount_code: 'WINTER20',
  payment_method: 'stripe',
  error_reason: 'Insufficient Funds',
  item_count: 4
)
```

**Flutter**

```dart
Sentry.logger.error('Checkout failed', attributes: {
  'userId': '882',
  'orderId': 'order_pc_991',
  'cartTotal': 142.50,
  'discountCode': 'WINTER20',
  'paymentMethod': 'stripe',
  'errorReason': 'Insufficient Funds',
  'itemCount': 4,
});
```

**Swift**

```swift
import Sentry

SentrySDK.logger.error("Checkout failed", attributes: [
    "userId": "882",
    "orderId": "order_pc_991",
    "cartTotal": 142.50,
    "discountCode": "WINTER20",
    "paymentMethod": "stripe",
    "errorReason": "Insufficient Funds",
    "itemCount": 4
])
```

**Kotlin**

```kotlin
import io.sentry.Sentry
import io.sentry.SentryAttribute
import io.sentry.SentryAttributes
import io.sentry.SentryLogLevel
import io.sentry.logger.SentryLogParameters

Sentry.logger().log(
    SentryLogLevel.ERROR,
    SentryLogParameters.create(
        SentryAttributes.of(
            SentryAttribute.stringAttribute("userId", "882"),
            SentryAttribute.stringAttribute("orderId", "order_pc_991"),
            SentryAttribute.doubleAttribute("cartTotal", 142.50),
            SentryAttribute.stringAttribute("discountCode", "WINTER20"),
            SentryAttribute.stringAttribute("paymentMethod", "stripe"),
            SentryAttribute.stringAttribute("errorReason", "Insufficient Funds"),
            SentryAttribute.integerAttribute("itemCount", 4)
        )
    ),
    "Checkout failed"
)
```

One log tells the whole story. Search for the error and get full context.

### [Log Drains for Platform Logs](https://docs.sentry.io/guides/logs.md#log-drains-for-platform-logs)

If you can't install the Sentry SDK or need platform-level logs (CDN, database, load balancer), use [Log Drains](https://docs.sentry.io/product/drains.md).

**Platform drains:** [Vercel](https://docs.sentry.io/product/drains/vercel.md), [Cloudflare Workers](https://docs.sentry.io/product/drains/cloudflare.md), [Heroku](https://docs.sentry.io/product/drains/heroku.md), [Supabase](https://docs.sentry.io/product/drains/supabase.md)

**Forwarders:** [OpenTelemetry Collector](https://docs.sentry.io/concepts/otlp/forwarding/pipelines/collector.md), [Vector](https://docs.sentry.io/concepts/otlp/forwarding/pipelines/vector.md), [Fluent Bit](https://docs.sentry.io/concepts/otlp/forwarding/pipelines/fluentbit.md), [AWS CloudWatch](https://docs.sentry.io/concepts/otlp/forwarding/sources/aws-cloudwatch.md), [Kafka](https://docs.sentry.io/concepts/otlp/forwarding/sources/kafka.md)

## [Quick Reference](https://docs.sentry.io/guides/logs.md#quick-reference)

| Category        | Level          | Example Attributes                  |
| --------------- | -------------- | ----------------------------------- |
| Auth events     | `info`/`warn`  | userId, authMethod, reason          |
| Payments        | `info`/`error` | orderId, amount, gateway, errorCode |
| External APIs   | `info`         | service, endpoint, durationMs       |
| Background jobs | `info`/`error` | jobType, jobId, retryCount          |
| Feature flags   | `info`         | flag, enabled, changedKeys          |

## [Next Steps](https://docs.sentry.io/guides/logs.md#next-steps)

Explore the [Logs product walkthrough guides](https://docs.sentry.io/product/explore/logs.md) to learn more about the Sentry interface and discover additional tips.
