sfcoe-ailabs
Version:
AI-powered code review tool with static analysis integration for comprehensive code quality assessment.
282 lines (281 loc) • 9.01 kB
JavaScript
import * as process from 'node:process';
import { DatadogLogger, } from '../observability/logging/index.js';
import { DatadogMetrics, } from '../observability/metrics/index.js';
import { DATADOG_DEFAULT_CONSTANTS } from './constants.js';
/**
* Centralized logger utility for debug and error logging
* This serves as a facade to the Datadog logger backend
*/
export class Logger {
static initialized = false;
/**
* Initialize the logger with Datadog configuration
*
* @param config - The Datadog logger configuration object
* @returns The initialized Winston logger instance
*/
static initialize(config) {
if (this.initialized) {
return DatadogLogger.getInstance();
}
const logger = DatadogLogger.initialize(config);
this.initialized = true;
return logger;
}
/**
* Check if logger is initialized
*
* @returns True if the logger is initialized, false otherwise
*/
static isInitialized() {
return this.initialized;
}
/**
* Log debug messages (only when debug is enabled)
*
* @param message - The debug message to log
* @param args - Additional arguments to include in the log metadata
*/
static debug(message, ...args) {
const meta = this.argsToMeta(args);
DatadogLogger.debug(message, meta);
}
/**
* Log info messages
*/
static info(message, ...args) {
const meta = this.argsToMeta(args);
DatadogLogger.info(message, meta);
}
/**
* Log warning messages
*/
static warn(message, ...args) {
const meta = this.argsToMeta(args);
DatadogLogger.warn(message, meta);
}
/**
* Log error messages
*/
static error(message, ...args) {
const meta = this.argsToMeta(args);
// Handle error objects in the args
const errorArg = args.find((arg) => arg instanceof Error);
if (errorArg) {
DatadogLogger.error(message, errorArg);
}
else {
DatadogLogger.error(message, meta);
}
}
/**
* Log with custom level and metadata (backward compatibility)
*/
static log(level, message, ...args) {
const meta = this.argsToMeta(args);
DatadogLogger.log(level, message, meta);
}
/**
* Convert variadic arguments to metadata object for structured logging
*/
static argsToMeta(args) {
if (args.length === 0) {
return {};
}
// If first argument is already an object, use it
if (args.length === 1 &&
typeof args[0] === 'object' &&
args[0] !== null &&
!Array.isArray(args[0])) {
return args[0];
}
// Convert args to indexed object
const meta = {};
args.forEach((arg) => {
if (arg instanceof Error) {
meta['error'] = {
message: arg.message,
stack: arg.stack,
name: arg.name,
};
}
else {
meta['data'] = arg;
}
});
return meta;
}
}
/**
* High-level metrics utility for the application
* This serves as a facade to the Datadog metrics backend
*/
export class Metrics {
static initialized = false;
/**
* Initialize the metrics system with Datadog configuration
*/
static initialize(config) {
if (this.initialized) {
return;
}
DatadogMetrics.initialize(config);
this.initialized = true;
}
/**
* Check if metrics system is initialized
*/
static isInitialized() {
return this.initialized;
}
/**
* Send a counter metric
*/
static increment(metric, value = 1, tags = []) {
DatadogMetrics.increment(metric, value, tags);
}
/**
* Send a decrement metric
*/
static decrement(metric, value = 1, tags = []) {
DatadogMetrics.decrement(metric, value, tags);
}
/**
* Send a gauge metric
*/
static gauge(metric, value, tags = []) {
DatadogMetrics.gauge(metric, value, tags);
}
/**
* Send a histogram metric
*/
static histogram(metric, value, tags = []) {
DatadogMetrics.histogram(metric, value, tags);
}
/**
* Send a timing metric
*/
static timing(metric, value, tags = []) {
DatadogMetrics.timing(metric, value, tags);
}
/**
* Send a distribution metric
*/
static distribution(metric, value, tags = []) {
DatadogMetrics.distribution(metric, value, tags);
}
/**
* Send a set metric
*/
static set(metric, value, tags = []) {
DatadogMetrics.set(metric, value, tags);
}
/**
* Flush buffered metrics immediately
*/
static flush() {
DatadogMetrics.flush();
}
/**
* Close the metrics client
*/
static close() {
DatadogMetrics.close();
}
}
/**
* Utility to initialize observability components (logging and metrics)
*/
export class ObservabilityInitializer {
static initialized = false;
/**
* Initialize both logging and metrics with provided configuration
*
* @param flags Record of command flags that will be included in logs and metrics.
* The following flags are included by default:
* - pull-request-id: Added as pullRequestId in logs and pull-request-id tag in metrics
* - repo-dir: Added as repoDir in logs and repo-dir tag in metrics
* - from: Added as from in logs and from tag in metrics
* - to: Added as to in logs and to tag in metrics
* - ai-provider: Added as aiProvider in logs and ai-provider tag in metrics
* - ai-model: Added as aiModel in logs and ai-model tag in metrics
* - git-provider: Added as gitProvider in logs and git-provider tag in metrics
* - git-owner: Added as gitOwner in logs and git-owner tag in metrics
* - git-repo: Added as gitRepo in logs and git-repo tag in metrics
*
* @example
* ```typescript
* // Basic usage with command flags
* ObservabilityInitializer.initialize(flags);
*
* // Usage with custom flags object
* ObservabilityInitializer.initialize({
* 'pull-request-id': '123',
* 'ai-provider': 'OpenAI',
* 'custom-flag': 'custom-value' // This won't be included unless added to default list
* });
* ```
*/
static initialize(flags) {
if (this.initialized) {
return;
}
// Build configuration
const config = this.buildConfigFromEnv(flags);
// Initialize logger
Logger.initialize(config.logger);
// Initialize metrics
Metrics.initialize(config.metrics);
// Mark as initialized
this.initialized = true;
}
/**
* Check if observability is initialized
*/
static isInitialized() {
return this.initialized;
}
/**
* Get default flags to include in observability metadata
*/
static getDefaultFlagsToInclude() {
return [...DATADOG_DEFAULT_CONSTANTS.observabilityFlags];
}
/**
* Build configuration from environment variables and flags with custom flag inclusion
*/
static buildConfigFromEnv(flags) {
const flagsToInclude = this.getDefaultFlagsToInclude();
// Build custom metadata from flags
const customMeta = {};
if (flags) {
for (const flagKey of flagsToInclude) {
const flagValue = flags[flagKey];
if (flagValue !== undefined && flagValue !== null && flagValue !== '') {
customMeta[flagKey] = flagValue;
}
}
}
return {
logger: {
apiKey: process.env.DD_API_KEY ?? '',
ddsource: process.env.DD_SOURCE ?? DATADOG_DEFAULT_CONSTANTS.ddsource,
hostname: process.env.DD_HOSTNAME ?? DATADOG_DEFAULT_CONSTANTS.hostname,
service: process.env.DD_SERVICE ?? DATADOG_DEFAULT_CONSTANTS.service,
environment: process.env.DD_ENV ?? DATADOG_DEFAULT_CONSTANTS.environment,
logLevel: process.env.LOG_LEVEL ?? DATADOG_DEFAULT_CONSTANTS.logLevel,
customMeta,
},
metrics: {
apiKey: process.env.DD_API_KEY ?? '',
host: process.env.DD_HOSTNAME ?? DATADOG_DEFAULT_CONSTANTS.hostname,
prefix: `${process.env.DD_METRIC_PREFIX ?? DATADOG_DEFAULT_CONSTANTS.prefix}.`,
globalTags: [
`source:${process.env.DD_SOURCE ?? DATADOG_DEFAULT_CONSTANTS.ddsource}`,
`service:${process.env.DD_SERVICE ?? DATADOG_DEFAULT_CONSTANTS.service}`,
`env:${DATADOG_DEFAULT_CONSTANTS.environment}`,
],
},
};
}
}