mirror of
https://github.com/HeyPuter/puter.git
synced 2025-01-23 22:40:20 +08:00
dev: add a feature to hook tracing into context
This commit is contained in:
parent
c2b094a351
commit
08dbef7b8c
21
src/backend/src/modules/core/ContextService.js
Normal file
21
src/backend/src/modules/core/ContextService.js
Normal file
@ -0,0 +1,21 @@
|
||||
const BaseService = require("../../services/BaseService");
|
||||
const { Context } = require("../../util/context");
|
||||
|
||||
/**
|
||||
* ContextService provides a way for other services to register a hook to be
|
||||
* called when a context/subcontext is created.
|
||||
*
|
||||
* Contexts are used to provide contextual information in the execution
|
||||
* context (dynamic scope). They can also be used to identify a "span";
|
||||
* a span is a labelled frame of execution that can be used to track
|
||||
* performance, errors, and other metrics.
|
||||
*/
|
||||
class ContextService extends BaseService {
|
||||
register_context_hook (event, hook) {
|
||||
Context.context_hooks_[event].push(hook);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
ContextService,
|
||||
};
|
@ -50,6 +50,9 @@ class Core2Module extends AdvancedBase {
|
||||
|
||||
const { ParameterService } = require("./ParameterService.js");
|
||||
services.registerService('params', ParameterService);
|
||||
|
||||
const { ContextService } = require('./ContextService.js');
|
||||
services.registerService('context', ContextService);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,13 @@ class Context {
|
||||
static USE_NAME_FALLBACK = {};
|
||||
static next_name_ = 0;
|
||||
static other_next_names_ = {};
|
||||
|
||||
// Context hooks should be registered via service (ContextService.js)
|
||||
static context_hooks_ = {
|
||||
pre_create: [],
|
||||
post_create: [],
|
||||
pre_arun: [],
|
||||
};
|
||||
|
||||
static contextAsyncLocalStorage = new AsyncLocalStorage();
|
||||
static __last_context_key = 0;
|
||||
@ -59,8 +66,8 @@ class Context {
|
||||
static describe () {
|
||||
return this.get().describe();
|
||||
}
|
||||
static arun (cb) {
|
||||
return this.get().arun(cb);
|
||||
static arun (...a) {
|
||||
return this.get().arun(...a);
|
||||
}
|
||||
static sub (values, opt_name) {
|
||||
return this.get().sub(values, opt_name);
|
||||
@ -72,6 +79,14 @@ class Context {
|
||||
this.values_[k] = v;
|
||||
}
|
||||
sub (values, opt_name) {
|
||||
if ( typeof values === 'string' ) {
|
||||
opt_name = values;
|
||||
values = {};
|
||||
}
|
||||
const name = opt_name ?? this.name ?? this.get('name');
|
||||
for ( const hook of this.constructor.context_hooks_.pre_create ) {
|
||||
hook({ values, name });
|
||||
}
|
||||
return new Context(values, this, opt_name);
|
||||
}
|
||||
get values () {
|
||||
@ -99,6 +114,7 @@ class Context {
|
||||
|
||||
opt_parent = opt_parent || Context.root;
|
||||
|
||||
this.trace_name = opt_name ?? undefined;
|
||||
this.name = (() => {
|
||||
if ( opt_name === this.constructor.USE_NAME_FALLBACK ) {
|
||||
opt_name = 'F';
|
||||
@ -129,7 +145,34 @@ class Context {
|
||||
|
||||
this.values_ = values;
|
||||
}
|
||||
async arun (cb) {
|
||||
async arun (...args) {
|
||||
let cb = args.shift();
|
||||
|
||||
let hints = {};
|
||||
if ( typeof cb === 'object' ) {
|
||||
hints = cb;
|
||||
cb = args.shift();
|
||||
}
|
||||
|
||||
if ( typeof cb === 'string' ) {
|
||||
const sub_context = this.sub(cb);
|
||||
return await sub_context.arun({ trace: true }, ...args);
|
||||
}
|
||||
|
||||
const replace_callback = new_cb => {
|
||||
cb = new_cb;
|
||||
}
|
||||
|
||||
for ( const hook of this.constructor.context_hooks_.pre_arun ) {
|
||||
hook({
|
||||
hints,
|
||||
name: this.name ?? this.get('name'),
|
||||
trace_name: this.trace_name,
|
||||
replace_callback,
|
||||
callback: cb,
|
||||
});
|
||||
}
|
||||
|
||||
const als = this.constructor.contextAsyncLocalStorage;
|
||||
return await als.run(new Map(), async () => {
|
||||
als.getStore().set('context', this);
|
||||
|
Loading…
Reference in New Issue
Block a user