CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-ledgerhq--logs

Ledger logs central point for unified logging system across Ledger libraries

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

index.mddocs/

@ledgerhq/logs

@ledgerhq/logs is a unified logging system for all Ledger libraries, providing centralized log dispatching and management across the Ledger Live ecosystem. It offers core logging functionality with the log() function for basic logging, a trace() function for capturing contextual information, and a LocalTracer class for maintaining persistent context across multiple log calls.

Package Information

  • Package Name: @ledgerhq/logs
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install @ledgerhq/logs

Core Imports

import { log, trace, listen, LocalTracer, type Log, type TraceContext } from "@ledgerhq/logs";

For CommonJS:

const { log, trace, listen, LocalTracer } = require("@ledgerhq/logs");

Basic Usage

import { log, trace, listen, LocalTracer } from "@ledgerhq/logs";

// Basic logging
log("apdu-in", "Received APDU command", { command: "0x80040000" });

// Enhanced logging with context
trace({
  type: "hw-connection",
  message: "Device connected",
  data: { deviceId: "nano-s-001" },
  context: { sessionId: "abc123" }
});

// Listen to all log events
const unsubscribe = listen((logEntry) => {
  console.log(`[${logEntry.type}] ${logEntry.message}`, logEntry.data);
});

// Tracer for maintaining context
const tracer = new LocalTracer("wallet-sync", { userId: "user123" });
tracer.trace("Starting sync", { accountCount: 5 });

Capabilities

Basic Logging

Core logging function for dispatching log events across the system.

/**
 * Logs something
 * @param type - A namespaced identifier of the log (not a level like "debug", "error" but more like "apdu-in", "apdu-out", etc...)
 * @param message - A clear message of the log associated to the type
 * @param data - Optional data associated to the log event
 */
function log(type: LogType, message?: string, data?: LogData): void;

Enhanced Tracing

Advanced logging function that captures more context than the basic log function.

/**
 * A simple tracer function, only expanding the existing log function
 * @param params - Object containing trace information
 */
function trace(params: {
  type: LogType;
  message?: string;
  data?: LogData;
  context?: TraceContext;
}): void;

Event Subscription

Subscribe to log events with callback functions for processing or forwarding logs.

/**
 * Adds a subscriber to the emitted logs
 * @param cb - Callback function called for each future log() with the Log object
 * @returns Function that can be called to unsubscribe the listener
 */
function listen(cb: Subscriber): Unsubscribe;

Local Tracer Class

Class-based tracer for maintaining persistent context across multiple log calls.

/**
 * A simple tracer class, that can be used to avoid repetition when using the `trace` function
 */
class LocalTracer {
  /**
   * Creates a new LocalTracer instance
   * @param type - A given type (not level) for the current local tracer ("hw", "withDevice", etc.)
   * @param context - Anything representing the context where the log occurred
   */
  constructor(type: LogType, context?: TraceContext);

  /**
   * Trace a message with the tracer's type and context
   * @param message - Log message
   * @param data - Optional additional data (Note: signature uses TraceContext but data is passed as LogData to trace function)
   */
  trace(message: string, data?: TraceContext): void;

  /**
   * Get the current context
   * @returns Current context or undefined
   */
  getContext(): TraceContext | undefined;

  /**
   * Set the context (mutates instance)
   * @param context - New context
   */
  setContext(context?: TraceContext): void;

  /**
   * Merge additional context (mutates instance)
   * @param contextToAdd - Context to merge with existing context
   */
  updateContext(contextToAdd: TraceContext): void;

  /**
   * Get the current log type
   * @returns Current log type
   */
  getType(): LogType;

  /**
   * Set the log type (mutates instance)
   * @param type - New log type
   */
  setType(type: LogType): void;

  /**
   * Create a new instance with an updated type (immutable)
   * @param type - New log type
   * @returns New LocalTracer instance
   */
  withType(type: LogType): LocalTracer;

  /**
   * Create a new instance with a new context (immutable)
   * @param context - New context (can be undefined to reset)
   * @returns New LocalTracer instance
   */
  withContext(context?: TraceContext): LocalTracer;

  /**
   * Create a new instance with an updated context (immutable)
   * @param contextToAdd - Context to merge with existing context
   * @returns New LocalTracer instance
   */
  withUpdatedContext(contextToAdd: TraceContext): LocalTracer;
}

Types

/**
 * Context data structure for tracing system
 */
type TraceContext = Record<string, unknown>;

/**
 * Data associated with log events
 */
type LogData = any;

/**
 * Namespaced identifier for log types
 */
type LogType = string;

/**
 * Core log object structure
 */
interface Log {
  /** A namespaced identifier of the log (not a level like "debug", "error" but more like "apdu", "hw", etc...) */
  type: LogType;
  /** Optional log message */
  message?: string;
  /** Data associated to the log event */
  data?: LogData;
  /** Context data, coming for example from the caller's parent, to enable a simple tracing system */
  context?: TraceContext;
  /** Unique id among all logs */
  id: string;
  /** Date when the log occurred */
  date: Date;
}

/**
 * Function to unsubscribe from log events
 */
type Unsubscribe = () => void;

/**
 * Callback function for log event subscribers
 */
type Subscriber = (log: Log) => void;

Usage Examples

Multi-step Process Logging

import { LocalTracer } from "@ledgerhq/logs";

// Create a tracer for a specific operation
const syncTracer = new LocalTracer("account-sync", {
  userId: "user123",
  sessionId: "session456"
});

// Log start of operation
syncTracer.trace("Starting account synchronization");

// Log progress with additional data
syncTracer.trace("Fetching account data", { accountId: "acc789" });

// Create new tracer for sub-operation
const apiTracer = syncTracer.withType("api-call");
apiTracer.trace("Calling accounts endpoint", { 
  url: "/api/accounts",
  method: "GET"
});

// Log completion
syncTracer.trace("Account synchronization completed", {
  duration: 1250,
  accountsUpdated: 3
});

Event Processing Pipeline

import { log, listen } from "@ledgerhq/logs";

// Set up log processing
const unsubscribe = listen((logEntry) => {
  // Forward critical logs to monitoring service
  if (logEntry.type.includes("error") || logEntry.type.includes("critical")) {
    sendToMonitoring(logEntry);
  }
  
  // Store all logs in local database
  saveToDatabase(logEntry);
  
  // Debug output in development
  if (process.env.NODE_ENV === "development") {
    console.log(`[${logEntry.date.toISOString()}] ${logEntry.type}: ${logEntry.message}`);
  }
});

// Emit various log types throughout application
log("device-connection", "Hardware wallet connected", { deviceType: "Nano S" });
log("transaction-broadcast", "Transaction sent to network", { txHash: "0x..." });
log("error-recovery", "Recovered from network error", { attempts: 3 });

// Clean up when done
unsubscribe();

Context Propagation

import { LocalTracer } from "@ledgerhq/logs";

class WalletService {
  private tracer: LocalTracer;

  constructor(userId: string) {
    this.tracer = new LocalTracer("wallet-service", { userId });
  }

  async processTransaction(txData: any) {
    // Create operation-specific tracer
    const txTracer = this.tracer.withUpdatedContext({
      operation: "process-transaction",
      txId: txData.id
    });

    txTracer.trace("Starting transaction processing");

    try {
      // Validation step
      const validationTracer = txTracer.withType("validation");
      validationTracer.trace("Validating transaction data");
      
      // Processing step
      const processingTracer = txTracer.withType("processing");
      processingTracer.trace("Processing transaction", { amount: txData.amount });
      
      txTracer.trace("Transaction processed successfully");
    } catch (error) {
      txTracer.trace("Transaction processing failed", { error: error.message });
      throw error;
    }
  }
}

Browser Integration

When used in browser environments, @ledgerhq/logs automatically exposes the listen function globally for debugging purposes:

// Available in browser console for debugging
window.__ledgerLogsListen((log) => {
  console.log("Debug log:", log);
});

docs

index.md

tile.json