How to Programmatically Destroy a Web‑Tracing Instance: Complete Cleanup Guide

Call the destroy() method on your WebTracing instance to clear timers, remove event listeners, close WebSocket connections, and flush pending telemetry.

When working with the m-cheng-web/web-tracing library, properly terminating your tracing session is critical to prevent memory leaks and ensure all telemetry data reaches your backend. The library maintains active timers, DOM event listeners, and persistent network connections that continue running until explicitly stopped. Understanding how to programmatically destroy a web-tracing instance ensures your application can cleanly shut down tracing during SPA navigation, user logout, or test teardown without leaving orphaned resources.

Why You Must Explicitly Destroy Web‑Tracing Instances

The Web‑Tracing library creates a singleton-style object that registers listeners, starts a background sampler, and opens a WebSocket (or HTTP) connection to the tracing backend. Without proper cleanup:

  • Interval timers and requestAnimationFrame callbacks continue firing indefinitely
  • Event listeners attached via window.addEventListener and document.addEventListener accumulate
  • Open WebSocket or EventSource connections remain active, consuming network resources
  • Internal buffers retain references, preventing garbage collection

Calling destroy() is the only officially supported method to release these resources and allow the JavaScript engine to reclaim memory.

How the destroy() Method Works Internally

In src/web-tracing.ts, the destroy() method implements a systematic teardown sequence. The implementation ensures that every component registered during initialization is properly reversed.

Stopping the Background Sampler

The tracing instance starts a sampling loop via this._sampler.start() during construction. During destruction, destroy() calls this._sampler.stop() (implemented in src/sampler.ts) to cancel the interval or requestAnimationFrame loop immediately.

Removing Registered Event Listeners

The instance maintains an internal registry this._registeredListeners containing all DOM events subscribed during initialization. The destroy() method iterates this collection and invokes removeEventListener for each entry, ensuring no tracing-related handlers remain attached to window or document.

Closing Network Connections

If the instance established a WebSocket connection (this._socket), the method executes socket.close() to terminate the transport gracefully. This step also closes any active EventSource or fetch-based long-polling connections opened for trace submission.

Flushing Pending Telemetry

Before clearing state, destroy() executes await this._flushPending() to transmit any buffered spans to the configured endpoint. This asynchronous flush ensures no trace data is lost during shutdown, returning a Promise that resolves once the network operation completes.

Code Examples for Destroying Web‑Tracing

Class-Based Instance

When instantiating WebTracing directly, store the reference and await the cleanup:

import { WebTracing } from "web-tracing";

const tracing = new WebTracing({
  endpoint: "https://tracing.example.com/collect",
  sampleRate: 0.5,
});

tracing.startSpan("page-load");

// Later, when tracing is no longer needed:
await tracing.destroy();

After destroy() resolves, the tracing variable holds no active timers, listeners, or connections.

Default Singleton

If using the default exported singleton from src/index.ts, invoke destroy directly on the imported object:

import tracing from "web-tracing";

// Application logic here...

await tracing.destroy();

Key Source Files in web-tracing

Understanding the source structure helps debug cleanup issues:

  • src/web-tracing.ts – Core WebTracing class containing the constructor, start, destroy, and internal helper methods such as _flushPending()
  • src/sampler.ts – Implements Sampler.start() and Sampler.stop() methods that control the background collection loop
  • src/index.ts – Public entry point exporting both the class and default singleton instance

These files collectively define the lifecycle management that makes programmatic destruction possible.

Summary

  • The WebTracing class exposes a destroy() method that performs complete cleanup of the tracing instance
  • Timers and samplers are stopped via this._sampler.stop() to prevent further execution
  • Event listeners are removed by iterating this._registeredListeners and calling removeEventListener
  • Network connections are closed through socket.close() and similar transport-specific methods
  • Pending data is flushed asynchronously via _flushPending() before returning
  • After destruction, the instance can be garbage collected and the library safely reinitialized

Frequently Asked Questions

What happens if I don't call destroy() on my WebTracing instance?

If you fail to call destroy(), the instance continues running background timers, maintaining DOM event listeners, and keeping WebSocket connections open. This leads to memory leaks in single-page applications and can cause duplicate data submission if you attempt to create a new instance without cleaning up the old one.

Can I restart tracing after calling destroy()?

Yes, but you must create a fresh instance. Once destroy() completes, the original instance becomes inert and cannot be restarted. Instantiate new WebTracing(config) again to begin collecting traces, which is particularly useful in test suites or when switching between user contexts.

Is the destroy() method synchronous or asynchronous?

The destroy() method is asynchronous and returns a Promise. It awaits the completion of this._flushPending() to ensure all buffered telemetry reaches the backend before resolving. Always use await tracing.destroy() or handle the returned Promise to guarantee cleanup completes before proceeding.

Does destroy() remove all trace data stored locally?

The destroy() method flushes pending spans to the server but does not explicitly wipe historical data from browser storage mechanisms like localStorage or IndexedDB if the library uses them. It primarily concerns runtime resources—timers, listeners, and connections—rather than persistent storage cleanup.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →