perf(telemetry): load telemetry asap (#1431)
Reviewed-on: daoyoucloud/tachybase#1431 Reviewed-by: sealday <zhanglin@daoyoucloud.com> Co-authored-by: TomyJan <TomyJan6@gmail.com> Co-committed-by: TomyJan <TomyJan6@gmail.com>
This commit is contained in:
parent
e5156a44a9
commit
d5a0f5640c
@ -11,7 +11,8 @@
|
||||
"@tachybase/preset-hera-sancongtou": "workspace:*",
|
||||
"@tachybase/preset-mini": "workspace:*",
|
||||
"@tachybase/preset-tachybase": "workspace:*",
|
||||
"@tachybase/server": "workspace:*"
|
||||
"@tachybase/server": "workspace:*",
|
||||
"@tachybase/telemetry": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tachybase/cache": "workspace:*",
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { telemetryOptions as telemetry } from '@tachybase/telemetry';
|
||||
|
||||
import { cacheManager } from './cache';
|
||||
import { parseDatabaseOptions } from './database';
|
||||
import logger from './logger';
|
||||
import plugins from './plugins';
|
||||
import resourcer from './resourcer';
|
||||
import { telemetry } from './telemetry';
|
||||
|
||||
export async function getConfig() {
|
||||
return {
|
||||
|
@ -1,3 +1,5 @@
|
||||
import '@tachybase/telemetry'; // 尽早实例化,以尽力保证插桩成功,TODO: Koa 依然无法成功 hook
|
||||
|
||||
import { Gateway } from '@tachybase/server';
|
||||
|
||||
import { getConfig } from './config';
|
||||
|
@ -17,7 +17,7 @@ import {
|
||||
SystemLoggerOptions,
|
||||
} from '@tachybase/logger';
|
||||
import { ResourceOptions, Resourcer } from '@tachybase/resourcer';
|
||||
import { Telemetry, TelemetryOptions } from '@tachybase/telemetry';
|
||||
import { AppTelemetryOptions, getTelemetry } from '@tachybase/telemetry';
|
||||
import { applyMixins, AsyncEmitter, importModule, Toposort, ToposortOptions } from '@tachybase/utils';
|
||||
|
||||
import { Command, CommandOptions, ParseOptions } from 'commander';
|
||||
@ -67,10 +67,6 @@ export interface AppLoggerOptions {
|
||||
system: SystemLoggerOptions;
|
||||
}
|
||||
|
||||
export interface AppTelemetryOptions extends TelemetryOptions {
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
export interface ApplicationOptions {
|
||||
database?: IDatabaseOptions | Database;
|
||||
cacheManager?: CacheManagerOptions;
|
||||
@ -310,10 +306,8 @@ export class Application<StateT = DefaultState, ContextT = DefaultContext> exten
|
||||
return this._locales;
|
||||
}
|
||||
|
||||
protected _telemetry: Telemetry;
|
||||
|
||||
get telemetry() {
|
||||
return this._telemetry;
|
||||
return getTelemetry();
|
||||
}
|
||||
|
||||
protected _version: ApplicationVersion;
|
||||
@ -516,12 +510,12 @@ export class Application<StateT = DefaultState, ContextT = DefaultContext> exten
|
||||
await this.emitAsync('beforeLoad', this, options);
|
||||
}
|
||||
|
||||
// Telemetry is initialized after beforeLoad hook
|
||||
// since some configuration may be registered in beforeLoad hook
|
||||
this.telemetry.init();
|
||||
// Telemetry is already initialized in @tachybase/app
|
||||
if (this.options.telemetry?.enabled) {
|
||||
// Start collecting telemetry data if enabled
|
||||
this.telemetry.start();
|
||||
if (!this.telemetry.started) {
|
||||
this.telemetry.start();
|
||||
}
|
||||
}
|
||||
|
||||
await this.pm.load(options);
|
||||
@ -1071,11 +1065,6 @@ export class Application<StateT = DefaultState, ContextT = DefaultContext> exten
|
||||
this.log.warn('TELEMETRY_SERVICE_NAME is not set, will use default service name, please set it in .env file!');
|
||||
serviceName = `tachybase-${this.name}`;
|
||||
}
|
||||
this._telemetry = new Telemetry({
|
||||
serviceName,
|
||||
version: this.getVersion(),
|
||||
...options.telemetry,
|
||||
});
|
||||
|
||||
this._authManager = new AuthManager({
|
||||
authKey: 'X-Authenticator',
|
||||
|
@ -1,6 +1,4 @@
|
||||
import { AppTelemetryOptions } from '@tachybase/server';
|
||||
|
||||
export const telemetry: AppTelemetryOptions = {
|
||||
export const telemetryOptions = {
|
||||
enabled: process.env.TELEMETRY_ENABLED === 'on',
|
||||
metric: {
|
||||
readerName: process.env.OTEL_METRICS_READER,
|
@ -1 +1,7 @@
|
||||
import { getTelemetry } from './telemetry';
|
||||
|
||||
if (!getTelemetry()) {
|
||||
throw new Error('Failed to load telemetry');
|
||||
}
|
||||
|
||||
export * from './telemetry';
|
||||
|
@ -74,17 +74,31 @@ export class Metric {
|
||||
console.warn('Prometheus server is disabled');
|
||||
} else {
|
||||
const port = Number(process.env.OTEL_PROMETHEUS_PORT) || 9464;
|
||||
const reader = () =>
|
||||
new PrometheusExporter(
|
||||
{
|
||||
port, // optional - default is 9464
|
||||
},
|
||||
() => {
|
||||
console.log(`Prometheus exporter endpoint started on http://localhost:${port}/metrics`);
|
||||
},
|
||||
);
|
||||
// 注册 Prometheus 作为指标 Reader
|
||||
this.registerReader('prometheus', reader);
|
||||
if (port <= 0 || port >= 65536) {
|
||||
throw new Error(`Invalid port: ${port}`);
|
||||
}
|
||||
if (port <= 1024) {
|
||||
console.warn('Prometheus server will try to run on a privileged port, it may need root permission');
|
||||
}
|
||||
if (port === 9464) {
|
||||
console.warn('Prometheus server will run on default port 9464');
|
||||
}
|
||||
try {
|
||||
// 启动 Prometheus Exporter
|
||||
const reader = () =>
|
||||
new PrometheusExporter(
|
||||
{
|
||||
port,
|
||||
},
|
||||
() => {
|
||||
console.log(`Prometheus exporter endpoint started on http://localhost:${port}/metrics`);
|
||||
},
|
||||
);
|
||||
// 注册 Prometheus Exporter 作为指标 Reader
|
||||
this.registerReader('prometheus', reader);
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize Prometheus metrics reader:', error);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize Prometheus metrics reader:', error);
|
||||
|
@ -4,9 +4,14 @@ import { InstrumentationOption, registerInstrumentations } from '@opentelemetry/
|
||||
import { Resource } from '@opentelemetry/resources';
|
||||
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
|
||||
|
||||
// 防止加载什么奇怪的东西
|
||||
import packageJson from '../../../../package.json';
|
||||
import { telemetryOptions } from './config';
|
||||
import { Metric, MetricOptions } from './metric';
|
||||
import { Trace, TraceOptions } from './trace';
|
||||
|
||||
export { telemetryOptions } from './config';
|
||||
|
||||
export interface TelemetryOptions {
|
||||
serviceName?: string;
|
||||
version?: string;
|
||||
@ -14,6 +19,10 @@ export interface TelemetryOptions {
|
||||
metric?: MetricOptions;
|
||||
}
|
||||
|
||||
export interface AppTelemetryOptions extends TelemetryOptions {
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
export class Telemetry {
|
||||
serviceName: string;
|
||||
version: string;
|
||||
@ -23,14 +32,13 @@ export class Telemetry {
|
||||
started = false;
|
||||
|
||||
constructor(options?: TelemetryOptions) {
|
||||
console.log('Create telemetry with options', options);
|
||||
const { trace, metric, serviceName, version } = options || {};
|
||||
this.trace = new Trace({ tracerName: `${serviceName}-trace`, version, ...trace });
|
||||
this.metric = new Metric({ meterName: `${serviceName}-meter`, version, ...metric });
|
||||
this.serviceName = serviceName || 'tachybase';
|
||||
this.serviceName = serviceName || 'tachybase-main';
|
||||
this.version = version || '';
|
||||
}
|
||||
|
||||
init() {
|
||||
// 设置 OTel 日志等级
|
||||
const diagLogLevel = process.env.OTEL_LOG_LEVEL;
|
||||
if (diagLogLevel) {
|
||||
@ -51,6 +59,10 @@ export class Telemetry {
|
||||
registerInstrumentations({
|
||||
instrumentations: this.instrumentations,
|
||||
});
|
||||
}
|
||||
|
||||
init() {
|
||||
console.log('Start init telemetry', this.serviceName, this.version);
|
||||
|
||||
const resource = Resource.default().merge(
|
||||
new Resource({
|
||||
@ -80,3 +92,25 @@ export class Telemetry {
|
||||
this.instrumentations.push(...instrumentation);
|
||||
}
|
||||
}
|
||||
|
||||
let _telemetry: Telemetry;
|
||||
|
||||
let serviceName = process.env.TELEMETRY_SERVICE_NAME;
|
||||
if (!serviceName) {
|
||||
console.warn('TELEMETRY_SERVICE_NAME is not set, will use default service name, please set it in .env file!');
|
||||
serviceName = `tachybase-main`;
|
||||
}
|
||||
|
||||
export const getTelemetry = () => {
|
||||
if (!_telemetry || typeof _telemetry === 'undefined') {
|
||||
_telemetry = new Telemetry({
|
||||
serviceName,
|
||||
version: packageJson.version || 'UnkVer',
|
||||
...telemetryOptions,
|
||||
});
|
||||
_telemetry.init();
|
||||
}
|
||||
// 这里只需要 init,start 保留在 application 里
|
||||
|
||||
return _telemetry;
|
||||
};
|
||||
|
2074
pnpm-lock.yaml
2074
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user