Skip to content

FlowTracer Quick Start

Get function execution tracing working in 5 minutes.

Prerequisites

  • JavaScript/TypeScript project
  • Node.js 18+ installed
  • Build tool (Vite, Webpack, etc.)
  • Package manager (pnpm, npm, or yarn)

Enterprise usage pattern

In large apps, the limiting factor is usually console output volume and DevTools rendering. Enable tracing only right before the action you want to observe, keep the scope narrow (include/exclude filters), then disable it immediately. In browser-based apps, the recommended runtime control surface for this workflow is the Dashboard. The dashboard controls tracing, but it does not display trace output by itself.

Step 1: Install Packages

Install the runtime, plus the build plugin for your platform.

bash
# Using pnpm (recommended)
pnpm add @autotracer/flow
pnpm add -D @autotracer/plugin-vite-flow @babel/core @babel/preset-typescript
# or (for Babel/Webpack)
pnpm add -D @autotracer/plugin-babel-flow @babel/core

# Using npm
npm install @autotracer/flow
npm install --save-dev @autotracer/plugin-vite-flow @babel/core @babel/preset-typescript
# or (for Babel/Webpack)
npm install --save-dev @autotracer/plugin-babel-flow @babel/core

# Using yarn
yarn add @autotracer/flow
yarn add -D @autotracer/plugin-vite-flow @babel/core @babel/preset-typescript
# or (for Babel/Webpack)
yarn add -D @autotracer/plugin-babel-flow @babel/core

@autotracer/logger installs automatically with @autotracer/flow.

Step 2: Configure Build Plugin

For Vite

This quickstart opts out of the dormant default so you can confirm installation immediately.

typescript
// vite.config.ts
import { defineConfig } from "vite";
import { flowTracer } from "@autotracer/plugin-vite-flow";

export default defineConfig(({ mode }) => ({
  plugins: [
    flowTracer({
      inject: mode === "development",
      runtimeControlled: false,
      include: {
        paths: ["src/**/*.ts", "src/**/*.tsx"],
      },
    }),
  ],
}));

The default exclusions already skip common test files, build outputs, coverage folders, and dependency folders.

For Webpack

bash
pnpm add -D @autotracer/plugin-babel-flow @babel/core
javascript
// babel.config.js
module.exports = {
  plugins: [
    [
      "@autotracer/plugin-babel-flow",
      {
        include: {
          paths: ["src/**/*.js"],
        },
      },
    ],
  ],
};

Use FlowTracer Babel settings for the exact Babel option behavior.

Step 3: Initialize Runtime

For Vite, no manual runtime initialization is required. For Babel/Webpack entry points, lazy-load the runtime before loading the rest of your app:

typescript
// src/main.ts or src/index.ts
const isDevelopment = process.env.NODE_ENV === "development";
const isInternalQa = process.env.REACT_APP_INTERNAL_QA === "true";

async function bootstrap(): Promise<void> {
  if (isDevelopment || isInternalQa) {
    await import("@autotracer/flow");
  }

  await import("./app");
}

void bootstrap();

Notes:

  • Vite: When using @autotracer/plugin-vite-flow, you do not need to add this import manually. The plugin injects @autotracer/flow/runtime when runtimeControlled is true or omitted, and @autotracer/flow when runtimeControlled is false.
  • Babel/Webpack: Use a compile-time-removable flag and import the rest of your app after the intended runtime entry so globalThis.__flowTracer exists before instrumented code runs. Use @autotracer/flow for immediate startup or @autotracer/flow/runtime for dormant startup.

For larger apps and restricted internal test or QA environments, switch back to dormant mode after the initial smoke test. That usually means runtimeControlled: true in Vite, or importing @autotracer/flow/runtime in your bootstrap path for Babel-based setups.

Step 4: Write Traceable Code

Create a simple example to see tracing in action:

typescript
// src/calculator.ts
export function calculateTotal(items: Array<{ price: number }>) {
  return items.reduce((sum, item) => sum + item.price, 0);
}

export function applyDiscount(total: number, discount: number) {
  return total * (1 - discount);
}

// src/main.ts
import { calculateTotal, applyDiscount } from "./calculator";

const items = [{ price: 10 }, { price: 20 }, { price: 30 }];

const total = calculateTotal(items);
const discounted = applyDiscount(total, 0.1);

console.log("Final price:", discounted);

Step 5: Run and See Results

bash
# For Vite
pnpm dev

# For Webpack
pnpm start

Expected Console Output:

→ calculateTotal
param items: [{"price":10},{"price":20},{"price":30}]
returned: 60
← calculateTotal (elapsed: 0.5ms)

→ applyDiscount
param total: 60
param discount: 0.1
returned: 54
← applyDiscount (elapsed: 0.3ms)

Final price: 54

Parameter Labels

The build plugin uses function names and parameter names when it injects trace calls.

typescript
function processOrder(order) {
  const validated = validateOrder(order);
  const discounted = applyDiscounts(order);
  return discounted;
}

Output with labels:

→ processOrder
param order: {"id":123,"total":100}
  → validateOrder
  param order: {"id":123,"total":100}
  returned: true
  ← validateOrder (elapsed: 0.2ms)
returned: {"id":123,"total":90}
← processOrder (elapsed: 0.6ms)

Configuration Options

Use these reference pages for configuration details:

Selective Tracing

Selective tracing is controlled by build-time filtering:

typescript
// vite.config.ts
import { defineConfig } from "vite";
import { flowTracer } from "@autotracer/plugin-vite-flow";

export default defineConfig({
  plugins: [
    flowTracer({
      include: {
        paths: ["src/business-logic/**/*.{ts,tsx,js,jsx}"],
        functions: ["calculate*", "process*"],
      },
      exclude: {
        functions: ["validate*"],
      },
    }),
  ],
});

Async Function Support

FlowTracer automatically handles async functions:

typescript
async function fetchUserData(userId: string) {
  const response = await fetch(`/api/users/${userId}`);
  return response.json();
}

const user = await fetchUserData("123");

Output:

→ fetchUserData (async started)
param userId: "123"
returned: Promise
← fetchUserData (async completed, elapsed: 142.7ms)

Troubleshooting

Not Seeing Output?

  1. Verify build plugin is configured correctly
  2. If using Babel/Webpack, ensure your intended runtime entry is imported in your entry file: @autotracer/flow for immediate startup or @autotracer/flow/runtime for dormant startup
  3. Ensure files match include.paths patterns
  4. For dormant mode, ensure the dormant runtime path is active: in Vite, keep inject enabled and leave runtimeControlled at true; in Babel/Webpack, import @autotracer/flow/runtime before the rest of the app, then start tracing through the Dashboard if it is mounted, or through globalThis.autoTracer.flowTracer.start() in non-Dashboard setups

Too Much Output?

Use more specific patterns:

typescript
// Build time - narrow what gets instrumented
// vite.config.ts (snippet)
import { flowTracer } from "@autotracer/plugin-vite-flow";

flowTracer({
  include: {
    paths: ["src/business-logic/**/*.{ts,tsx,js,jsx}"],
    functions: ["calculate*", "process*"],
  },
  exclude: {
    functions: ["validate*"],
  },
});

Performance Impact?

When tracing is active, overhead can be noticeable in large apps (often dominated by console output and DevTools rendering). To minimize:

typescript
// vite.config.ts
import { defineConfig } from "vite";
import { flowTracer } from "@autotracer/plugin-vite-flow";

export default defineConfig(({ mode }) => ({
  plugins: [
    flowTracer({
      inject: mode === "development",
    }),
  ],
}));

Example: API Integration

typescript
// src/api.ts
export async function loginUser(email: string, password: string) {
  const response = await fetch("/api/login", {
    method: "POST",
    body: JSON.stringify({ email, password }),
  });

  if (!response.ok) {
    throw new Error("Login failed");
  }

  return response.json();
}

// src/main.ts
import { loginUser } from "./api";

try {
  const user = await loginUser("alice@example.com", "password123");
  console.log("Logged in:", user);
} catch (error) {
  console.error("Login error:", error);
}

Console Output:

→ loginUser (async started)
param email: "alice@example.com"
param password: "password123"
returned: Promise
← loginUser (async completed, elapsed: 287.3ms)

Logged in: {id: 1, name: "Alice", token: "abc123..."}

Next Steps

Need Help?

Released under the MIT License.