LogTide

Error Handling

LogTide provides a standardized exception structure that works across all programming languages, enabling consistent error tracking, grouping, and analysis.

Overview

When you log errors with LogTide SDKs, exceptions are automatically serialized into a structured format stored in metadata.exception. This enables:

Stack Trace Parsing

Automatic parsing of stack frames with file, function, and line information.

Error Grouping

Similar errors are grouped by fingerprint for easier triage.

Language Agnostic

Works with Node.js, Python, Go, PHP, Kotlin, C#, Rust, Ruby, and more.

Exception Chaining

Support for nested/caused-by exceptions in languages that support them.

Structured Exceptions

When you pass an error to the SDK's logging methods, it automatically serializes the exception into the metadata.exception field:

// SDK automatically serializes the error
client.error('api', 'Request failed', new Error('Connection timeout'));

// Results in this log structure:
{
  "time": "2025-01-30T12:00:00Z",
  "service": "api",
  "level": "error",
  "message": "Request failed",
  "metadata": {
    "exception": {
      "type": "Error",
      "message": "Connection timeout",
      "language": "nodejs",
      "stacktrace": [
        { "file": "/app/src/api.ts", "function": "handleRequest", "line": 42 },
        { "file": "/app/src/server.ts", "function": "processRequest", "line": 128 }
      ],
      "raw": "Error: Connection timeout\n    at handleRequest (/app/src/api.ts:42:15)\n..."
    }
  }
}

Backward Compatibility

If you send errors without using the SDK (e.g., via HTTP API with stack traces in the message), LogTide will attempt to parse them using language-specific regex patterns as a fallback.

StructuredException Interface

The structured exception format is defined as follows. All SDKs serialize errors into this format:

interface StructuredException {
  /**
   * Exception type/class name
   * @example "TypeError", "NullPointerException", "ValueError"
   */
  type: string;

  /**
   * Human-readable error message
   */
  message: string;

  /**
   * Stack trace as an array of frames (top to bottom)
   * First frame = where the error was thrown
   */
  stacktrace?: StructuredStackFrame[];

  /**
   * Language hint for better fingerprinting
   * @example "nodejs", "python", "java", "go", "php", "kotlin", "csharp", "rust", "ruby"
   */
  language?: string;

  /**
   * Inner/cause exception (for wrapped exceptions)
   * @example Java's "Caused by", JavaScript's error.cause
   */
  cause?: StructuredException;

  /**
   * Additional exception metadata
   * @example { code: "ECONNREFUSED", errno: -111 }
   */
  metadata?: Record<string, unknown>;

  /**
   * Original raw stack trace as a string (fallback)
   */
  raw?: string;
}

interface StructuredStackFrame {
  /** File path or module name */
  file?: string;

  /** Function/method name */
  function?: string;

  /** Line number (1-based) */
  line?: number;

  /** Column number */
  column?: number;

  /** Additional frame metadata */
  metadata?: Record<string, unknown>;
}

SDK Examples

Node.js

import { LogTideClient } from '@logtide/sdk-node';

const client = new LogTideClient({
  apiUrl: 'https://logs.example.com',
  apiKey: 'lp_your_api_key',
  // Or use a DSN string instead:
  // dsn: 'https://[email protected]',
});

try {
  await riskyOperation();
} catch (error) {
  // Error is automatically serialized with stack trace
  client.error('api', 'Operation failed', error);
}

// With error.cause (Node.js 16.9+)
try {
  await fetchData();
} catch (error) {
  throw new Error('Failed to fetch user data', { cause: error });
}

Python

from logtide import LogTideClient

client = LogTideClient(
    api_url="https://logs.example.com",
    api_key="lp_your_api_key"
)

try:
    risky_operation()
except Exception as e:
    # Exception is automatically serialized with traceback
    client.error("api", "Operation failed", exc=e)

# With exception chaining
try:
    fetch_data()
except IOError as e:
    raise ValueError("Failed to fetch user data") from e

Go

import "github.com/logtide-dev/logtide-sdk-go"

client := logtide.NewClient(logtide.Config{
    ApiURL: "https://logs.example.com",
    ApiKey: "lp_your_api_key",
})

if err := riskyOperation(); err != nil {
    // Error is serialized with stack trace (if using pkg/errors or similar)
    client.Error("api", "Operation failed", logtide.WithError(err))
}

// With wrapped errors
if err := fetchData(); err != nil {
    return fmt.Errorf("failed to fetch user data: %w", err)
}

Manual HTTP (No SDK)

If you're not using an SDK, you can manually structure the exception in your metadata:

{
  "logs": [{
    "time": "2025-01-30T12:00:00Z",
    "service": "api",
    "level": "error",
    "message": "Request failed",
    "metadata": {
      "exception": {
        "type": "ConnectionError",
        "message": "Failed to connect to database",
        "language": "python",
        "stacktrace": [
          { "file": "app/db.py", "function": "connect", "line": 45 },
          { "file": "app/api.py", "function": "handle_request", "line": 123 }
        ]
      }
    }
  }]
}

Fallback Behavior

When LogTide receives an error log, it processes exceptions in this order:

  1. Structured metadata.exception — Preferred. Parsed directly without regex.
  2. Text-based parsing — Falls back to regex parsing of the message field for known stack trace formats.

Text-based parsing supports these languages:

Node.js (V8)
Python
Java
Go
PHP

Recommendation

For best results, use an official SDK which handles serialization automatically. Text-based parsing may not work for custom log formatters or unsupported languages.

Best Practices

1. Always Pass the Error Object
Pass the actual error/exception object to the SDK, not just the message. This preserves the full stack trace and error type.
2. Use Error Chaining
When wrapping errors, use your language's error chaining mechanism (error.cause in JS, raise ... from in Python, %w in Go) to preserve the original error context.
3. Add Contextual Metadata
Include relevant context like user ID, request ID, or operation parameters in the metadata to help with debugging.
4. Use Appropriate Log Levels
Use error for recoverable errors and critical for unrecoverable/fatal errors. Exception tracking is only enabled for these levels.