
Security News
CVE Volume Surges Past 48,000 in 2025 as WordPress Plugin Ecosystem Drives Growth
CVE disclosures hit a record 48,185 in 2025, driven largely by vulnerabilities in third-party WordPress plugins.
@auriclabs/metrics
Advanced tools
A TypeScript metrics collection and visualization package for tracking function execution times, errors, and performance statistics with beautiful hierarchical tree displays.
api.users.get)span helper for both sync and async function trackingpnpm add @auriclabs/metrics
cli-table3 - For professional table formatting with borderschalk - For color-coded outputlodash-es - For utility functionsimport { recordMetrics, displayMetrics } from '@auriclabs/metrics';
// Record a metric manually
recordMetrics('api.users.get', 145.23);
// Record with error
recordMetrics('api.users.create', 230.45, new Error('Validation failed'));
// Display all metrics
displayMetrics();
import { span, displayMetrics } from '@auriclabs/metrics';
async function getUserData(userId: string) {
return await span('api.users.get', async () => {
// Your async code here
const user = await fetchUserFromDatabase(userId);
return user; // Return values are preserved
});
}
async function createUser(userData: UserData) {
return await span('api.users.create', async () => {
// Your async code here
const newUser = await saveUserToDatabase(userData);
return newUser; // Return values are preserved
});
}
// After execution
displayMetrics();
The span function automatically preserves return values from both sync and async functions:
import { span } from '@auriclabs/metrics';
// Synchronous function with return value
const result = span('calculate', () => {
return 42 * 2;
});
console.log(result); // 84
// Async function with return value
const user = await span('fetchUser', async () => {
return await db.users.findById('123');
});
console.log(user); // User object
// Mixed sync and async spans
const total = await span('processOrder', async () => {
const price = span('calculatePrice', () => 100); // Sync
const tax = await span('fetchTax', async () => 10); // Async
return price + tax;
});
console.log(total); // 110
import { span } from '@auriclabs/metrics';
async function handleRequest() {
await span('api', async () => {
await span('request', async () => {
await span('auth', async () => {
// Authentication logic
// This creates metric: api.request.auth
});
await span('validation', async () => {
// Validation logic
// This creates metric: api.request.validation
});
await span('processing', async () => {
// Processing logic
// This creates metric: api.request.processing
});
});
});
}
The displayMetrics() function produces two sections:
═══ Metrics Summary ═══
┌─────────────┬────────────────┬──────────────┬──────────────┐
│ Total Calls │ Total Duration │ Total Errors │ Avg Duration │
├─────────────┼────────────────┼──────────────┼──────────────┤
│ 42 │ 1234.56ms │ 3 │ 29.39ms │
└─────────────┴────────────────┴──────────────┴──────────────┘
Tree structure with Unicode box-drawing characters in the first column, followed by all metrics:
═══ Metrics Tree ═══
┌──────────────────────────────────┬────────┬────────────┬────────────┬────────────┬────────────┬────────┐
│ Span │ Calls │ Avg │ Min │ Max │ Total │ Errors │
├──────────────────────────────────┼────────┼────────────┼────────────┼────────────┼────────────┼────────┤
│ ├── api │ 15 │ 145.23ms │ 100.00ms │ 200.00ms │ 2178.45ms │ 0 │
│ │ ├── users │ 8 │ 230.45ms │ 180.00ms │ 300.00ms │ 1843.60ms │ 2 │
│ │ │ ├── get │ 7 │ 142.50ms │ 100.00ms │ 200.00ms │ 997.50ms │ 0 │
│ │ │ └── create │ 1 │ 846.10ms │ 846.10ms │ 846.10ms │ 846.10ms │ 2 │
│ │ └── posts │ 5 │ 150.00ms │ 130.00ms │ 180.00ms │ 750.00ms │ 0 │
│ │ ├── list │ 3 │ 80.12ms │ 60.00ms │ 120.00ms │ 240.36ms │ 0 │
│ │ └── create │ 2 │ 254.82ms │ 180.00ms │ 329.64ms │ 509.64ms │ 0 │
│ └── database │ 4 │ 50.00ms │ 40.00ms │ 65.00ms │ 200.00ms │ 0 │
│ └── query │ 4 │ 50.00ms │ 40.00ms │ 65.00ms │ 200.00ms │ 0 │
└──────────────────────────────────┴────────┴────────────┴────────────┴────────────┴────────────┴────────┘
recordMetrics(name: string, duration: number, error?: unknown)Manually record a metric.
Parameters:
name: Dot-separated metric name (e.g., 'api.users.get')duration: Execution duration in millisecondserror (optional): Error object if the operation failedgetMetrics(): Record<string, MetricsRecord>Get all recorded metrics as a plain object.
Returns: Object with metric names as keys and MetricsRecord objects as values.
displayMetrics()Display all metrics in a beautiful formatted output with:
span<T>(name: string, fn: () => T | Promise<T>): T | Promise<T>Execute a synchronous or asynchronous function and automatically record its execution time.
Parameters:
name: Metric name for this spanfn: Function to execute (can be sync or async)Returns: The return value from the wrapped function (preserves both sync and async returns)
Features:
parent.child.grandchild)Examples:
// Synchronous function
const result = span('math.add', () => 1 + 1); // Returns: 2
// Asynchronous function
const data = await span('api.fetch', async () => {
return await fetch('/api/data');
}); // Returns: Response object
// Nested spans with return values
const user = await span('users', async () => {
const id = span('generateId', () => uuid()); // Sync
return await span('save', async () => {
return await db.users.insert({ id }); // Async
});
});
interface MetricsRecord {
totalRecords: number; // Number of times this metric was recorded
totalDuration: number; // Sum of all durations
averageDuration: number; // Average duration per call
maxDuration: number; // Maximum duration observed
minDuration: number; // Minimum duration observed
duration: number; // Last recorded duration
totalErrors: number; // Count of errors
lastError?: unknown; // Last error object
}
The display uses color coding for better readability:
import { span, displayMetrics } from '@auriclabs/metrics';
import express from 'express';
const app = express();
app.use(async (req, res, next) => {
await span('http', async () => {
await span(req.method, async () => {
await span(req.path, async () => {
next();
});
});
});
});
// Display metrics on shutdown
process.on('SIGTERM', () => {
displayMetrics();
process.exit(0);
});
import { span } from '@auriclabs/metrics';
class UserRepository {
async findById(id: string): Promise<User | null> {
return await span('database', async () => {
return await span('users', async () => {
return await span('findById', async () => {
// Return value is preserved through all nested spans
return await this.db.users.findOne({ id });
});
});
});
}
async create(user: User): Promise<User> {
return await span('database', async () => {
return await span('users', async () => {
return await span('create', async () => {
// Validates before inserting
const isValid = span('validate', () => this.validate(user)); // Sync span
if (!isValid) throw new Error('Invalid user');
// Return the created user
return await this.db.users.insert(user);
});
});
});
}
}
// Usage - all return values work as expected
const user = await userRepo.findById('123');
if (user) {
console.log(user.name);
}
const newUser = await userRepo.create({ name: 'Alice', email: 'alice@example.com' });
console.log(newUser.id); // Newly created user ID
ISC
FAQs
Metrics for AuricLabs projects
We found that @auriclabs/metrics demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
CVE disclosures hit a record 48,185 in 2025, driven largely by vulnerabilities in third-party WordPress plugins.

Security News
Socket CEO Feross Aboukhadijeh joins Insecure Agents to discuss CVE remediation and why supply chain attacks require a different security approach.

Security News
Tailwind Labs laid off 75% of its engineering team after revenue dropped 80%, as LLMs redirect traffic away from documentation where developers discover paid products.