[core] Add browser tracing debug API

This commit is contained in:
devlikepro committed 2025-07-02 14:45:52 +07:00
1 parent 38b542def4
commit 873e66db19
5 files changed
+93 -2

No files matched your search

+39 -2
View File
@@ -5,10 +5,21 @@ import {
Get,
Logger,
NotFoundException,
Query,
StreamableFile,
UsePipes,
} from '@nestjs/common';
import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger';
import { WhatsappConfigService } from '@waha/config.service';
import { SessionManager } from '@waha/core/abc/manager.abc';
import { WhatsappSession } from '@waha/core/abc/session.abc';
import {
SessionApiParam,
WorkingSessionParam,
} from '@waha/nestjs/params/SessionApiParam';
import { WAHAValidationPipe } from '@waha/nestjs/pipes/WAHAValidationPipe';
import { BrowserTracingQuery } from '@waha/structures/server.debug.dto';
import { createReadStream } from 'fs';
@ApiSecurity('api_key')
@Controller('api/server/debug')
@@ -17,14 +28,17 @@ export class ServerDebugController {
private logger: Logger;
private readonly enabled: boolean;
constructor(protected config: WhatsappConfigService) {
constructor(
private config: WhatsappConfigService,
private manager: SessionManager,
) {
this.logger = new Logger('ServerDebugController');
this.enabled = this.config.debugModeEnabled;
}
@Get('heapsnapshot')
@ApiOperation({
summary: 'Return a heapsnapshot',
summary: 'Return a heapsnapshot for the current nodejs process',
description: "Return a heapsnapshot of the server's memory",
})
async heapsnapshot() {
@@ -39,4 +53,27 @@ export class ServerDebugController {
disposition: `attachment; filename=${fileName}`,
});
}
@Get('browser/tracing/:session')
@ApiOperation({
summary: 'Collect and get a trace.json for Chrome DevTools ',
description: 'Uses https://pptr.dev/api/puppeteer.tracing',
})
@SessionApiParam
@UsePipes(new WAHAValidationPipe())
async browserTracing(
@WorkingSessionParam session: WhatsappSession,
@Query() query: BrowserTracingQuery,
) {
if (!this.enabled) {
throw new NotFoundException('WAHA_DEBUG_MODE is disabled');
}
const filepath = await session.browserTracing(query);
const stream = createReadStream(filepath);
const filename = `trace - ${session.name} - ${new Date()}.json`;
return new StreamableFile(stream, {
type: 'application/octet-stream',
disposition: `attachment; filename=${filename}`,
});
}
}
+5
View File
@@ -30,6 +30,7 @@ import { Label, LabelDTO, LabelID } from '@waha/structures/labels.dto';
import { LidToPhoneNumber } from '@waha/structures/lids.dto';
import { PaginationParams } from '@waha/structures/pagination.dto';
import { MessageSource, WAMessage } from '@waha/structures/responses.dto';
import { BrowserTracingQuery } from '@waha/structures/server.debug.dto';
import { DefaultMap } from '@waha/utils/DefaultMap';
import { generatePrefixedId } from '@waha/utils/ids';
import { LoggerBuilder } from '@waha/utils/logging';
@@ -349,6 +350,10 @@ export abstract class WhatsappSession {
* START - Methods for API
*/
public browserTracing(query: BrowserTracingQuery): Promise<string> {
throw new NotImplementedByEngineError();
}
/**
* Auth methods
*/
+4
View File
@@ -119,4 +119,8 @@ export class WPage extends EventEmitter {
this.page.on(event, listener);
return this.page as any;
}
get tracing() {
return this.page.tracing;
}
}
@@ -106,6 +106,7 @@ import {
WAHAPresenceData,
} from '@waha/structures/presence.dto';
import { WAMessage, WAMessageReaction } from '@waha/structures/responses.dto';
import { BrowserTracingQuery } from '@waha/structures/server.debug.dto';
import { MeInfo } from '@waha/structures/sessions.dto';
import { StatusRequest, TextStatus } from '@waha/structures/status.dto';
import {
@@ -117,7 +118,9 @@ import {
import { PaginatorInMemory } from '@waha/utils/Paginator';
import { sleep, waitUntil } from '@waha/utils/promiseTimeout';
import { SingleDelayedJobRunner } from '@waha/utils/SingleDelayedJobRunner';
import { TmpDir } from '@waha/utils/tmpdir';
import * as lodash from 'lodash';
import * as path from 'path';
import { ProtocolError } from 'puppeteer';
import { filter, fromEvent, merge, mergeMap, Observable, share } from 'rxjs';
import { map } from 'rxjs/operators';
@@ -519,6 +522,23 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
/**
* START - Methods for API
*/
public async browserTracing(query: BrowserTracingQuery): Promise<string> {
const tmpdir = new TmpDir(
this.logger,
`waha-browser-tracing-${this.name}`,
(10 * query.seconds + 120) * 1000,
);
const page = this.whatsapp.pupPage;
return await tmpdir.use(async (dir) => {
this.logger.info({ query }, `Starting browser tracing...`);
const filepath = path.join(dir, 'trace.json');
await page.tracing.start({ path: filepath });
await sleep(query.seconds * 1000);
await page.tracing.stop();
this.logger.info(`Browser tracing finished, saved to ${filepath}`);
return filepath;
});
}
/**
* Auth methods
+25
View File
@@ -0,0 +1,25 @@
import { ApiProperty } from '@nestjs/swagger';
import { Transform, Type } from 'class-transformer';
import { IsArray, IsNumber, IsOptional, IsString } from 'class-validator';
export class BrowserTracingQuery {
@Type(() => Number)
@IsNumber()
@ApiProperty({
description: 'How many seconds to trace',
example: 30,
required: true,
})
seconds: number = 30;
@IsArray()
@IsString({ each: true })
@Transform(({ value }) => (Array.isArray(value) ? value : [value]))
@IsOptional()
@ApiProperty({
description: 'Categories to trace (all by default)',
example: ['*'],
required: true,
})
categories: string[] = ['*'];
}