This commit is contained in:
Tutur33
2023-11-24 22:35:41 +01:00
parent 3c0b507a93
commit 7644b2a0f7
45165 changed files with 4803356 additions and 3 deletions
+24
View File
@@ -0,0 +1,24 @@
/// <reference path="../../adonis-typings/profiler.d.ts" />
import { ProfilerProcessor } from '@ioc:Adonis/Core/Profiler';
/**
* Profiler action is used to time the function. A connection can be
* connected to a row or can be a global action.
*/
export declare class ProfilerAction {
private label;
private processor;
private parentId?;
private data?;
private start;
private timestamp;
private ended;
constructor(label: string, processor: Exclude<ProfilerProcessor, string>, parentId?: string | undefined, data?: any);
/**
* Make packet for the action
*/
private makePacket;
/**
* End profiling action.
*/
end(data?: any): void;
}
+65
View File
@@ -0,0 +1,65 @@
"use strict";
/*
* @adonisjs/profiler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ProfilerAction = void 0;
/// <reference path="../../adonis-typings/profiler.ts" />
const utils_1 = require("@poppinss/utils");
/**
* Profiler action is used to time the function. A connection can be
* connected to a row or can be a global action.
*/
class ProfilerAction {
constructor(label, processor, parentId, data) {
this.label = label;
this.processor = processor;
this.parentId = parentId;
this.data = data;
this.start = process.hrtime();
this.timestamp = Date.now();
this.ended = false;
}
/**
* Make packet for the action
*/
makePacket() {
return {
parent_id: this.parentId,
type: 'action',
label: this.label,
timestamp: this.timestamp,
duration: process.hrtime(this.start),
data: this.data || {},
};
}
/**
* End profiling action.
*/
end(data) {
/**
* Raise error when end is called twice. Their are high probabilities of
* end getting called twice
*/
if (this.ended) {
throw new utils_1.Exception('attempt to end profiler action twice');
}
/**
* Set the flag
*/
this.ended = true;
/**
* Merge inline data if defined
*/
if (data) {
this.data = Object.assign({}, this.data, data);
}
this.processor(this.makePacket());
}
}
exports.ProfilerAction = ProfilerAction;
+28
View File
@@ -0,0 +1,28 @@
/// <reference path="../../adonis-typings/profiler.d.ts" />
import { ProfilerRowContract, ProfilerActionContract } from '@ioc:Adonis/Core/Profiler';
/**
* Dummy action is a noop implementation of [[ProfileActionContract]]. When
* actions for certain labels are disabled, then dummy action is used and
* helps in avoiding the need of unneccessary `if/else` clauses.
*/
declare class DummyAction implements ProfilerActionContract {
end(): void;
}
/**
* Dummy row is a noop implementation of [[ProfilerRowContract]]. When certain
* labels are disabled, then dummy row is used and helps in avoiding the need
* of unneccessary `if/else` clauses.
*/
declare class DummyRow implements ProfilerRowContract {
private action;
get hasParent(): boolean;
profile(action: string, data: any, cb: () => void): void;
profile(action: string, data?: any): ProfilerActionContract;
profileAsync(action: string, data: any, cb: () => void): Promise<void>;
profileAsync(action: string, data?: any): Promise<ProfilerActionContract>;
create(): this;
end(): void;
}
declare const dummyAction: DummyAction;
declare const dummyRow: DummyRow;
export { dummyAction, dummyRow };
+52
View File
@@ -0,0 +1,52 @@
"use strict";
/*
* @adonisjs/profiler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.dummyRow = exports.dummyAction = void 0;
/**
* Dummy action is a noop implementation of [[ProfileActionContract]]. When
* actions for certain labels are disabled, then dummy action is used and
* helps in avoiding the need of unneccessary `if/else` clauses.
*/
class DummyAction {
end() { }
}
/**
* Dummy row is a noop implementation of [[ProfilerRowContract]]. When certain
* labels are disabled, then dummy row is used and helps in avoiding the need
* of unneccessary `if/else` clauses.
*/
class DummyRow {
constructor() {
this.action = new DummyAction();
}
get hasParent() {
return false;
}
profile(_action, _data, cb) {
if (typeof cb === 'function') {
return cb();
}
return this.action;
}
async profileAsync(_action, _data, cb) {
if (typeof cb === 'function') {
return cb();
}
return this.action;
}
create() {
return this;
}
end() { }
}
const dummyAction = new DummyAction();
exports.dummyAction = dummyAction;
const dummyRow = new DummyRow();
exports.dummyRow = dummyRow;
@@ -0,0 +1,8 @@
import { Exception } from '@poppinss/utils';
export declare class InvalidProcessorException extends Exception {
/**
* Raised when the profiler worker doesn't exports the process
* function
*/
static missingWorkerMethod(): InvalidProcessorException;
}
@@ -0,0 +1,29 @@
"use strict";
/*
* @adonisjs/profiler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.InvalidProcessorException = void 0;
const utils_1 = require("@poppinss/utils");
const exceptions_json_1 = __importDefault(require("../../exceptions.json"));
class InvalidProcessorException extends utils_1.Exception {
/**
* Raised when the profiler worker doesn't exports the process
* function
*/
static missingWorkerMethod() {
const exception = exceptions_json_1.default['E_INVALID_PROFILER_WORKER'];
const error = new this(exception.message, exception.status, exception.code);
error.help = exception.help.join('\n');
return error;
}
}
exports.InvalidProcessorException = InvalidProcessorException;
@@ -0,0 +1,20 @@
/// <reference path="../../adonis-typings/profiler.d.ts" />
import { ProfilerActionContract, AbstractProfilerContract } from '@ioc:Adonis/Core/Profiler';
/**
* Abstract class to be extended to add support for timing functions.
*/
export declare abstract class AbstractProfiler implements AbstractProfilerContract {
protected abstract getAction(action: string, data: any): ProfilerActionContract;
/**
* Profile asyncronously. If you are are not passing a callback to this method,
* then consider using [[this.profile]].
*/
profileAsync<T extends any>(action: string, data: any, cb: () => Promise<T>): Promise<T>;
profileAsync(action: string, data?: any): Promise<ProfilerActionContract>;
/**
* Get a new profiler action instance to time your code. Make sure
* to call the `end` function, when manually managing the actions
*/
profile<T extends any>(action: string, data: any, cb: () => T): T;
profile(action: string, data?: any): ProfilerActionContract;
}
+47
View File
@@ -0,0 +1,47 @@
"use strict";
/*
* @adonisjs/profiler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.AbstractProfiler = void 0;
/**
* Abstract class to be extended to add support for timing functions.
*/
class AbstractProfiler {
async profileAsync(action, data, cb) {
const profilerAction = this.getAction(action, data);
if (typeof cb === 'function') {
try {
const result = await cb();
profilerAction.end();
return result;
}
catch (error) {
profilerAction.end({ error });
throw error;
}
}
return profilerAction;
}
profile(action, data, cb) {
const profilerAction = this.getAction(action, data);
if (typeof cb === 'function') {
try {
const result = cb();
profilerAction.end();
return result;
}
catch (error) {
profilerAction.end({ error });
throw error;
}
}
return profilerAction;
}
}
exports.AbstractProfiler = AbstractProfiler;
+47
View File
@@ -0,0 +1,47 @@
/// <reference path="../../adonis-typings/profiler.d.ts" />
import { LoggerContract } from '@ioc:Adonis/Core/Logger';
import { AbstractProfiler } from './AbstractProfiler';
import { ProfilerConfig, ProfilerContract, ProfilerProcessor, ProfilerRowContract, ProfilerActionContract } from '@ioc:Adonis/Core/Profiler';
/**
* Profiler exposes the public interface to create new profiling
* rows and actions. In case of blacklisted actions, dummy
* implementations are returned, resulting in noop.
*/
export declare class Profiler extends AbstractProfiler implements ProfilerContract {
private appRoot;
private logger;
private worker?;
/**
* Subscribe to listen for events
*/
processor?: Exclude<ProfilerProcessor, string>;
/**
* Profiler config
*/
private config;
constructor(appRoot: string, logger: LoggerContract, config: Partial<ProfilerConfig>);
/**
* Returns the action to be used for timing functions
*/
protected getAction(action: string, data?: any): ProfilerActionContract;
/**
* Returns a boolean telling if profiler is enabled for
* a given `action` or `label` or not?
*/
isEnabled(labelOrAction: string): boolean;
/**
* Creates a new profiler row for a given action. If action is not enabled
* then a copy of [[this.dummyRow]] is returned, which has the same
* public API with all actions to a noop.
*/
create(label: string, data?: any): ProfilerRowContract;
/**
* Close the worker and cleanup memory
*/
cleanup(): void;
/**
* Define subscriber for the profiler. Only one subscriber can be defined
* at max. Redifying the subscriber will override the existing subscriber
*/
process(fn: ProfilerProcessor): void;
}
+126
View File
@@ -0,0 +1,126 @@
"use strict";
/*
* @adonisjs/profiler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Profiler = void 0;
/// <reference path="../../adonis-typings/profiler.ts" />
const jest_worker_1 = require("jest-worker");
const helpers_1 = require("@poppinss/utils/build/helpers");
const Row_1 = require("../Row");
const Action_1 = require("../Action");
const AbstractProfiler_1 = require("./AbstractProfiler");
const DummyProfiler_1 = require("../DummyProfiler");
const InvalidProcessorException_1 = require("../Exceptions/InvalidProcessorException");
/**
* Profiler exposes the public interface to create new profiling
* rows and actions. In case of blacklisted actions, dummy
* implementations are returned, resulting in noop.
*/
class Profiler extends AbstractProfiler_1.AbstractProfiler {
constructor(appRoot, logger, config) {
super();
this.appRoot = appRoot;
this.logger = logger;
this.config = Object.assign({
enabled: true,
whitelist: [],
blacklist: [],
}, config);
}
/**
* Returns the action to be used for timing functions
*/
getAction(action, data) {
return this.isEnabled(action)
? new Action_1.ProfilerAction(action, this.processor, undefined, data)
: DummyProfiler_1.dummyAction;
}
/**
* Returns a boolean telling if profiler is enabled for
* a given `action` or `label` or not?
*/
isEnabled(labelOrAction) {
if (!this.config.enabled || !this.processor) {
return false;
}
/**
* If white list is empty, then check for blacklist
*/
if (this.config.whitelist.length === 0) {
return this.config.blacklist.indexOf(labelOrAction) === -1;
}
/**
* Otherwise check for whitelist only. We can check for `whitelist` and
* `blacklist` both here, but not 100% sure.
*/
return this.config.whitelist.indexOf(labelOrAction) > -1;
}
/**
* Creates a new profiler row for a given action. If action is not enabled
* then a copy of [[this.dummyRow]] is returned, which has the same
* public API with all actions to a noop.
*/
create(label, data) {
if (this.isEnabled(label)) {
return new Row_1.ProfilerRow(label, this, data);
}
return DummyProfiler_1.dummyRow;
}
/**
* Close the worker and cleanup memory
*/
cleanup() {
if (this.worker) {
this.worker.end();
}
this.processor = undefined;
this.worker = undefined;
}
/**
* Define subscriber for the profiler. Only one subscriber can be defined
* at max. Redifying the subscriber will override the existing subscriber
*/
process(fn) {
/**
* The processor is an inline function
*/
if (typeof fn === 'function') {
this.processor = async (log) => {
try {
await fn(log);
}
catch (error) {
this.logger.fatal(error, 'The profiler processor function raised an exception');
}
};
return;
}
this.worker = new jest_worker_1.Worker((0, helpers_1.resolveFrom)(this.appRoot, fn));
this.worker.getStdout().pipe(process.stdout);
this.worker.getStderr().pipe(process.stderr);
/**
* Ensure worker has "process" method on it
*/
if (typeof this.worker['process'] !== 'function') {
throw InvalidProcessorException_1.InvalidProcessorException.missingWorkerMethod();
}
/**
* The processor is a spawned worker (recommended)
*/
this.processor = async (log) => {
try {
await this.worker['process'](log);
}
catch (error) {
this.logger.fatal(error, `The profiler processor worker "${fn}" raised an exception`);
}
};
}
}
exports.Profiler = Profiler;
+40
View File
@@ -0,0 +1,40 @@
/// <reference path="../../adonis-typings/profiler.d.ts" />
import { AbstractProfiler } from '../Profiler/AbstractProfiler';
import { ProfilerContract, ProfilerRowContract, ProfilerActionContract } from '@ioc:Adonis/Core/Profiler';
/**
* Profiler row class is used to group profiling actions together. Any
* number of nested rows can be created.
*/
export declare class ProfilerRow extends AbstractProfiler implements ProfilerRowContract {
private label;
private manager;
private data?;
private parentId?;
private id;
private timestamp;
private start;
private ended;
constructor(label: string, manager: ProfilerContract, data?: any, parentId?: string | undefined);
/**
* Makes the log packet for the log row
*/
private makeLogPacket;
/**
* Returns the action instance to be used by the [[AbstractProfiler]] class
*/
protected getAction(action: string, data?: any): ProfilerActionContract;
/**
* Returns a boolean telling if a parent exists
*/
get hasParent(): boolean;
/**
* End the profiler instance by emitting end packet. After
* this all profiling calls will be considered overflows
*/
end(data?: any): void;
/**
* Get a new child logger. Child logger will emit a new row
* in the events timeline
*/
create(label: string, data?: any): ProfilerRowContract;
}
+102
View File
@@ -0,0 +1,102 @@
"use strict";
/*
* @adonisjs/profiler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ProfilerRow = void 0;
/// <reference path="../../adonis-typings/profiler.ts" />
const helpers_1 = require("@poppinss/utils/build/helpers");
const utils_1 = require("@poppinss/utils");
const Action_1 = require("../Action");
const DummyProfiler_1 = require("../DummyProfiler");
const AbstractProfiler_1 = require("../Profiler/AbstractProfiler");
/**
* Profiler row class is used to group profiling actions together. Any
* number of nested rows can be created.
*/
class ProfilerRow extends AbstractProfiler_1.AbstractProfiler {
constructor(label, manager, data, parentId) {
super();
this.label = label;
this.manager = manager;
this.data = data;
this.parentId = parentId;
this.id = (0, helpers_1.cuid)();
this.timestamp = Date.now();
this.start = process.hrtime();
this.ended = false;
}
/**
* Makes the log packet for the log row
*/
makeLogPacket() {
return {
id: this.id,
type: 'row',
label: this.label,
parent_id: this.parentId,
timestamp: this.timestamp,
data: this.data || {},
duration: process.hrtime(this.start),
};
}
/**
* Returns the action instance to be used by the [[AbstractProfiler]] class
*/
getAction(action, data) {
if (this.ended) {
throw new utils_1.Exception('cannot profile after parent row has been ended');
}
return this.manager.isEnabled(action)
? new Action_1.ProfilerAction(action, this.manager.processor, this.id, data)
: DummyProfiler_1.dummyAction;
}
/**
* Returns a boolean telling if a parent exists
*/
get hasParent() {
return !!this.parentId;
}
/**
* End the profiler instance by emitting end packet. After
* this all profiling calls will be considered overflows
*/
end(data) {
/**
* Raise error when end has been called already
*/
if (this.ended) {
throw new utils_1.Exception('attempt to end profiler row twice');
}
/**
* Setting end to true to avoid multiple calls
*/
this.ended = true;
/**
* Merge data
*/
if (data) {
this.data = Object.assign({}, this.data, data);
}
/**
* Invoke processor
*/
this.manager.processor(this.makeLogPacket());
}
/**
* Get a new child logger. Child logger will emit a new row
* in the events timeline
*/
create(label, data) {
if (this.manager.isEnabled(label)) {
return new ProfilerRow(label, this.manager, data, this.id);
}
return DummyProfiler_1.dummyRow;
}
}
exports.ProfilerRow = ProfilerRow;