Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[refactor] Better integrated logger. #109

Merged
merged 7 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ stateDiagram-v2
}

state core {
getLogger()
sharedHelpers
sharedConstants
types
Expand Down Expand Up @@ -163,7 +162,7 @@ Bootstrapping all the files you'll need to start coding.
yarn cli create-plugin
```

Then learn more about what you can use from [the ecosystem](/packages/core).
Then learn more about what you can use from [the ecosystem](/packages/factory).

## Tests

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ type GlobalContext = {
writeDuration?: number;
};
cwd: string;
getLogger: (name: string) => [Logger](/packages/factory/src/helpers.ts);
// Added in `buildStart`.
git?: {
hash: string;
Expand Down
45 changes: 0 additions & 45 deletions packages/core/src/log.ts

This file was deleted.

16 changes: 14 additions & 2 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export type SerializedOutput = Assign<Output, { inputs: string[] }>;
export type BuildReport = {
errors: string[];
warnings: string[];
logs: { pluginName: string; type: LogLevel; message: string; time: number }[];
entries?: Entry[];
inputs?: Input[];
outputs?: Output[];
Expand Down Expand Up @@ -73,12 +74,20 @@ export type BundlerReport = {

export type ToInjectItem = { type: 'file' | 'code'; value: string; fallback?: ToInjectItem };

export type Logger = {
error: (text: any) => void;
warn: (text: any) => void;
info: (text: any) => void;
debug: (text: any) => void;
};
export type GetLogger = (name: string) => Logger;
export type GlobalContext = {
auth?: AuthOptions;
inject: (item: ToInjectItem) => void;
bundler: BundlerReport;
build: BuildReport;
cwd: string;
getLogger: GetLogger;
git?: RepositoryData;
pluginNames: string[];
start: number;
Expand All @@ -103,13 +112,13 @@ export type AuthOptions = {
apiKey?: string;
};

export interface GetPluginsOptions {
export interface BaseOptions {
auth?: AuthOptions;
disableGit?: boolean;
logLevel?: LogLevel;
}

export interface Options extends GetPluginsOptions {
export interface Options extends BaseOptions {
// Each product should have a unique entry.
// #types-injection-marker
[rum.CONFIG_KEY]?: RumOptions;
Expand All @@ -118,6 +127,9 @@ export interface Options extends GetPluginsOptions {
customPlugins?: GetCustomPlugins;
}

export type GetPluginsOptions = Required<BaseOptions>;
export type OptionsWithDefaults = Assign<Options, GetPluginsOptions>;

export type PluginName = `datadog-${Lowercase<string>}-plugin`;

type Data = { data: BodyInit; headers?: Record<string, string> };
Expand Down
25 changes: 25 additions & 0 deletions packages/factory/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ This is used to aggregate all the plugins and expose them to the bundler.
- [Bundler Report](#bundler-report)
- [Git](#git)
- [Injection](#injection)
- [Logger](#logger)
- [Global Context](#global-context)
<!-- #toc -->

Expand Down Expand Up @@ -49,6 +50,29 @@ Most of the time they will interact via the global context.
<kbd>[📝 Full documentation ➡️](/packages/plugins/injection#readme)</kbd>
<!-- #internal-plugins-list -->

## Logger

If you need to log anything into the console you'll have to use the global Logger.
Simply instantiate your logger in your plugin's initialization.

```typescript
// ./packages/plugins/my-plugin/index.ts
[...]

export const getMyPlugins = (context: GlobalContext) => {
const logger = context.getLogger('my-plugin');
};
```

Then you can either use one of the level logger methods:

```typescript
logger.warn('This is also a warning');
logger.error('This is an error');
logger.info('This is an info');
logger.debug('This is a debug message');
```

## Global Context

A global, shared context within the build plugins ecosystem.<br/>
Expand Down Expand Up @@ -106,6 +130,7 @@ type GlobalContext = {
writeDuration?: number;
};
cwd: string;
getLogger: (name: string) => [Logger](/packages/factory/src/helpers.ts);
// Added in `buildStart`.
git?: {
hash: string;
Expand Down
1 change: 1 addition & 0 deletions packages/factory/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@dd/internal-injection-plugin": "workspace:*",
"@dd/rum-plugin": "workspace:*",
"@dd/telemetry-plugin": "workspace:*",
"chalk": "2.3.1",
"unplugin": "1.16.0"
}
}
79 changes: 70 additions & 9 deletions packages/factory/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,95 @@
// Copyright 2019-Present Datadog, Inc.

import type {
BuildReport,
BundlerFullName,
BundlerName,
FactoryMeta,
GetLogger,
GlobalContext,
LogLevel,
Options,
OptionsWithDefaults,
ToInjectItem,
} from '@dd/core/types';
import c from 'chalk';

const logPriority: Record<LogLevel, number> = {
debug: 0,
info: 1,
warn: 2,
error: 3,
none: 4,
};

// Exported for testing.
export const getLoggerFactory =
(build: BuildReport, logLevel: LogLevel = 'warn'): GetLogger =>
(name) => {
const log = (text: any, type: LogLevel = 'debug') => {
// By default (debug) we print dimmed.
let color = c.dim;
let logFn = console.log;

if (type === 'error') {
color = c.red;
logFn = console.error;
} else if (type === 'warn') {
color = c.yellow;
logFn = console.warn;
} else if (type === 'info') {
color = c.cyan;
logFn = console.log;
}

const prefix = `[${type}|${name}]`;

// Keep a trace of the log in the build report.
const content = typeof text === 'string' ? text : JSON.stringify(text, null, 2);
build.logs.push({ pluginName: name, type, message: content, time: Date.now() });
if (type === 'error') {
build.errors.push(content);
}
if (type === 'warn') {
build.warnings.push(content);
}

// Only log if the log level is high enough.
if (logPriority[type] >= logPriority[logLevel]) {
logFn(`${color(prefix)} ${content}`);
}
};

return {
error: (text: any) => log(text, 'error'),
warn: (text: any) => log(text, 'warn'),
info: (text: any) => log(text, 'info'),
debug: (text: any) => log(text, 'debug'),
};
};

export const getContext = ({
auth,
options,
bundlerName,
bundlerVersion,
injections,
version,
}: {
auth: Options['auth'];
options: OptionsWithDefaults;
bundlerName: BundlerName;
bundlerVersion: string;
injections: ToInjectItem[];
version: FactoryMeta['version'];
}): GlobalContext => {
const cwd = process.cwd();
const variant = bundlerName === 'webpack' ? bundlerVersion.split('.')[0] : '';

const build: BuildReport = {
errors: [],
warnings: [],
logs: [],
};
const context: GlobalContext = {
auth,
auth: options.auth,
pluginNames: [],
bundler: {
name: bundlerName,
Expand All @@ -37,22 +100,20 @@ export const getContext = ({
outDir: cwd,
version: bundlerVersion,
},
build: {
errors: [],
warnings: [],
},
build,
cwd,
inject: (item: ToInjectItem) => {
injections.push(item);
},
getLogger: getLoggerFactory(build, options.logLevel),
start: Date.now(),
version,
};

return context;
};

export const validateOptions = (options: Options = {}): Options => {
export const validateOptions = (options: Options = {}): OptionsWithDefaults => {
return {
auth: {},
disableGit: false,
Expand Down
9 changes: 5 additions & 4 deletions packages/factory/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type {
FactoryMeta,
GlobalContext,
Options,
OptionsWithDefaults,
PluginOptions,
ToInjectItem,
} from '@dd/core/types';
Expand Down Expand Up @@ -59,7 +60,7 @@ export const buildPluginFactory = ({
// TODO: Validate API Key and endpoint.
// TODO: Inject a metric logger into the global context.

const options = validateOptions(opts);
const options: OptionsWithDefaults = validateOptions(opts);

// Set the host name for the esbuild plugin.
if (unpluginMetaContext.framework === 'esbuild') {
Expand All @@ -69,7 +70,7 @@ export const buildPluginFactory = ({
// Create the global context.
const injections: ToInjectItem[] = [];
const context: GlobalContext = getContext({
auth: options.auth,
options,
bundlerVersion: bundler.version || bundler.VERSION,
bundlerName: unpluginMetaContext.framework as BundlerName,
injections,
Expand All @@ -83,10 +84,10 @@ export const buildPluginFactory = ({
const plugins: (PluginOptions | UnpluginOptions)[] = [
// Prefill with our internal plugins.
// #internal-plugins-injection-marker
...getBuildReportPlugins(options, context),
...getBuildReportPlugins(context),
...getBundlerReportPlugins(context),
...getGitPlugins(options, context),
...getInjectionPlugins(bundler, options, context, injections),
...getInjectionPlugins(bundler, context, injections),
// #internal-plugins-injection-marker
];

Expand Down
13 changes: 8 additions & 5 deletions packages/plugins/build-report/src/esbuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
// Copyright 2019-Present Datadog, Inc.

import { getResolvedPath, isInjectionFile } from '@dd/core/helpers';
import type { Logger } from '@dd/core/log';
import type { Entry, GlobalContext, Input, Output, PluginOptions } from '@dd/core/types';
import type { Logger, Entry, GlobalContext, Input, Output, PluginOptions } from '@dd/core/types';
import { glob } from 'glob';

import { cleanName, getAbsolutePath, getType } from './helpers';
Expand Down Expand Up @@ -68,12 +67,16 @@ export const getEsbuildPlugin = (context: GlobalContext, log: Logger): PluginOpt
const entryNames = getEntryNames(entrypoints, context);

build.onEnd((result) => {
context.build.errors = result.errors.map((err) => err.text);
context.build.warnings = result.warnings.map((err) => err.text);
for (const error of result.errors) {
context.build.errors.push(error.text);
}
for (const warning of result.warnings) {
context.build.warnings.push(warning.text);
}

const warn = (warning: string) => {
context.build.warnings.push(warning);
log(warning, 'warn');
log.warn(warning);
};

if (!result.metafile) {
Expand Down
2 changes: 2 additions & 0 deletions packages/plugins/build-report/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export const serializeBuildReport = (report: BuildReport): SerializedBuildReport
const jsonReport: SerializedBuildReport = {
errors: report.errors,
warnings: report.warnings,
logs: report.logs,
start: report.start,
end: report.end,
duration: report.duration,
Expand Down Expand Up @@ -103,6 +104,7 @@ export const unserializeBuildReport = (report: SerializedBuildReport): BuildRepo
const buildReport: BuildReport = {
errors: report.errors,
warnings: report.warnings,
logs: report.logs,
start: report.start,
end: report.end,
duration: report.duration,
Expand Down
Loading