Use loggers

Most of Workleap's frontend platform libraries can produce meaningful logs when provided with logger instances. Once configured, these libraries use a five-level logging system: debug, information, warning, error, and critical.

The following libraries integrate with loggers that implement the RootLogger interface 👇

Name Documentation
Squide Guide
Platform widgets Guide
Telemetry Reference
Common Room Reference

Log levels

A logger can output log entries with different levels: debug, information, warning, error, critical. This allows to filter logs according to a minimum severity:

import { BrowserConsoleLogger, LogLevel } from "@workleap/logging";

const logger = new BrowserConsoleLogger({
    logLevel: LogLevel.error
});

In the previous example, the logger instance would process only error and critical entries ☝️.

For development environments, we generally recommend setting the minimum severity to debug. For production environments, we recommend setting the minimum severity to information. The information level provides a good balance as it is detailed enough for basic troubleshooting, while reducing noise in production.

For reference, here's a description of each level:

Debug

  • Very detailed, often verbose, logs used mainly during development.
  • Example: API request/response bodies, lifecycle hooks, variable state.

Information

  • General events that show the normal flow of the application.
  • Example: User login, component mounted, scheduled task started.

Warning

  • Non-critical issues that might need attention but don't break functionality.
  • Example: Deprecated API usage, retries after a failed network call.

Error

  • Failures that prevent part of the system from working as intended.
  • Example: Unhandled exceptions, failed database query, API call failed with 500.

Critical

  • Severe errors that cause the application to stop functioning or risk data integrity.
  • Example: Application crash, loss of critical service connection.

Example

The following example shows how to integrate loggers into a Squide application (loggers are also supported in both React and non-React applications):

index.tsx
import { createRoot } from "react-dom/client";
import { initializeWidgets } from "@workleap-widgets/squide-firefly";
import { initializeFirefly, FireflyProvider } from "@squide/firefly";
import { BrowserConsoleLogger, LogLevel, type RootLogger } from "@workleap/logging";
import { LogRocketLogger, } from "@workleap/logrocket";
import { initializeTelemetry, TelemetryProvider } from "@workleap/telemetry/react";
import { registerCommonRoomInstrumentation } from "@workleap/common-room/react";

// Do not do this, it's only for demo purpose.
const isDev = process.env === "development";

const loggers: RootLogger[] = [isDev ? new BrowserConsoleLogger() : new LogRocketLogger(LogLevel.information)];

const telemetryClient = initializeTelemetry({
    logRocket: {
        appId: "my-app-id"
    },
    honeycomb: {
        namespace: "sample",
        serviceName: "my-app",
        apiServiceUrls: [/.+/g],
        options: {
            proxy: "https://sample-proxy"
        }
    },
    mixpanel: {
        productId: "wlp",
        envOrTrackingApiBaseUrl: "development"
    },
    loggers
});

registerCommonRoomInstrumentation("my-site-id", {
    loggers
});

// IMPORTANT: Squide loggers are propagated to platform widgets under the hood.
const fireflyRuntime = initializeFirefly({
    loggers
});

const widgetsRuntime = initializeWidgets(fireflyRuntime, "wlp", "development", {
    colorScheme: "light",
    language: "en-US",
    widgets: {
        fte: {
            invitationModal: true
        }
    }
});

const root = createRoot(document.getElementById("root")!);

root.render(
    <FireflyProvider runtime={runtime}>
        <TelemetryProvider client={telemetryClient}>
            <App />
        </TelemetryProvider>
    </FireflyProvider>
);

Troubleshoot a production issue

To troubleshoot an issue in production, remove the LogLevel from the LogRocketLogger constructor options and set the verbose option to true when applicable:

index.tsx
import { createRoot } from "react-dom/client";
import { initializeWidgets } from "@workleap-widgets/squide-firefly";
import { initializeFirefly, FireflyProvider } from "@squide/firefly";
import { BrowserConsoleLogger, type RootLogger } from "@workleap/logging";
import { LogRocketLogger, } from "@workleap/logrocket";
import { initializeTelemetry, TelemetryProvider } from "@workleap/telemetry/react";
import { registerCommonRoomInstrumentation } from "@workleap/common-room/react";

// Do not do this, it's only for demo purpose.
const isDev = process.env === "development";

const loggers: RootLogger[] = [isDev ? new BrowserConsoleLogger() : new LogRocketLogger()];

const telemetryClient = initializeTelemetry({
    logRocket: {
        appId: "my-app-id"
    },
    honeycomb: {
        namespace: "sample",
        serviceName: "my-app",
        apiServiceUrls: [/.+/g],
        options: {
            proxy: "https://sample-proxy"
        }
    },
    mixpanel: {
        productId: "wlp",
        envOrTrackingApiBaseUrl: "development"
    },
    verbose: true,
    loggers
});

registerCommonRoomInstrumentation("my-site-id", {
    verbose: true,
    loggers
});

// IMPORTANT: Squide loggers are propagated to platform widgets under the hood.
const fireflyRuntime = initializeFirefly({
    loggers
});

const widgetsRuntime = initializeWidgets(fireflyRuntime, "wlp", "development", {
    colorScheme: "light",
    language: "en-US",
    widgets: {
        fte: {
            invitationModal: true
        }
    },
    verbose: true
});

const root = createRoot(document.getElementById("root")!);

root.render(
    <FireflyProvider runtime={runtime}>
        <TelemetryProvider client={telemetryClient}>
            <App />
        </TelemetryProvider>
    </FireflyProvider>
);

Application logs

Once loggers are configured, Squide applications can write log entries using the FireflyRuntime instance:

import { useLogger } from "@squide/firefly";

const logger = useLogger();

logger.debug("Hello!");
import { useRuntime } from "@squide/firefly";

const runtime = useRuntime();

runtime.logger.debug("Hello!");