Logstory
Logstory is a flexible and extensible logger for JavaScript that allows easy integration of additional features and sending events to monitoring systems such as Sentry or Graylog.
Key Features:
- Easy Integration: The logger provides a convenient interface for embedding additional functions and middleware, allowing easy customization of its behavior according to the application's needs.
- Middleware Support: The logger allows passing middleware that can handle or send events when warnings or errors occur. This enables integration with monitoring systems such as Sentry or Graylog for centralized log collection and analysis.
- Configurable Log Level: The logger supports a customizable log level, allowing you to control the output of different message levels (debug, log, warn, error) based on your application requirements.
- Development Environment Support: The logger automatically adapts to the development environment, allowing you to manage the log level based on the environment (e.g., enabling debug messages only in development mode).
Installation:
Basic Usage:
createLogger.ts
import {
applyConsoleProxyMiddleware,
CreateLoggerParams,
createLogstory,
Logger,
LogLevelState,
MiddlewareFunction
} from '@37bytes/logstory';
const defaultLogLevelState: LogLevelState = {
debug: import.meta.env.DEV,
log: import.meta.env.DEV,
warn: true,
error: true
};
export const createSimplePureLogger = (name: CreateLoggerParams['name']): Logger =>
createLogstory({ name, logLevelState: defaultLogLevelState, consoleProxy: window.console });
if (import.meta.env.DEV) {
window.developingFeatures = window.developingFeatures || {};
window.developingFeatures.createLogger = createLogstory;
window.developingFeatures.createSimplePureLogger = createSimplePureLogger;
createSimplePureLogger('createLogger').debug(
'createLogger/createSimplePureLogger are available in window.developingFeatures'
);
}
Example.tsx
const pureLogger = createSimplePureLogger('Test')
useEffect(() => {
logger.debug('Debug message');
logger.log('Log message');
logger.warn('Warning message');
logger.error('Error message');
}, [])
Change the logger name format:
You can customize the logger output to suit your needs
Default output
logger.debug('Debug message');
logger.log('Log message');
logger.warn('Warning message');
logger.error('Error message');
Your custom output
const customLoggerName = ({ loggerName, logLevel }: FormatLoggerNameParams): string => {
if (logLevel === 'error') {
return `! ${loggerName} !`;
}
return `[${loggerName}]`;
};
const logger = createLogstory({ name: 'Feature', formatLoggerName: customLoggerName });
logger.debug('Debug message');
logger.log('Log message');
logger.warn('Warning message');
logger.error('Error message');
Advanced Usage:
If you want to use Sentry or GrayLog with your logger, create a special console proxy and apply the applyConsoleProxyMiddleware
function found in the package
createLogger.ts
import getTrackingServicesConsoleProxy from './getTrackingServicesConsoleProxy';
import {
applyConsoleProxyMiddleware,
CreateLoggerParams,
createLogstory,
Logger,
LogLevelState,
MiddlewareFunction
} from '@37bytes/logstory';
const defaultLogLevelState: LogLevelState = {
ebug: import.meta.env.DEV,
log: import.meta.env.DEV,
warn: true,
error: true
};
export enum MiddlewareExtras {
SENTRY = 'sentryExtra',
GREY_LOG = 'greylogExtra'
}
export type ApplyMiddlewareMessage = unknown;
export type ApplyMiddlewareExtras = {
[MiddlewareExtras.SENTRY]?: { tags: { loggerName: string } }
[MiddlewareExtras.GREY_LOG]?: { data: string[] }
};
export type MiddlewareFunctionCallbackType = MiddlewareFunction<ApplyMiddlewareMessage, ApplyMiddlewareExtras>;
const initSentry: MiddlewareFunctionCallbackType = ({ message, extras }) => {
const { sentryExtra } = extras;
Sentry.captureException(message, sentryExtra);
};
const initGrayLog: MiddlewareFunctionCallbackType = ({ message, extras }) => {
const { greylogExtra } = extras;
graylogLogger.warning(message as string, greylogExtra);
};
export const createSentryLogger = ({ name, logLevelState = defaultLogLevelState }: CreateLoggerParams = {}): Logger =>
createLogger({
name,
logLevelState,
consoleProxy: getTrackingServicesConsoleProxy(
name,
applyConsoleProxyMiddleware<ApplyMiddlewareMessage, ApplyMiddlewareExtras, MiddlewareFunctionCallbackType>([
initSentry,
initGrayLog
])
)
});
export const createSimpleSentryLogger = (name: CreateLoggerParams['name']) => createSentryLogger({ name });
if (import.meta.env.DEV) {
window.developingFeatures = window.developingFeatures || {};
window.developingFeatures.createSentryLogger = createSentryLogger;
window.developingFeatures.createSimpleSentryLogger = createSimpleSentryLogger;
createSimplePureLogger('createLogger').debug(
'createLogger/createSentryLogger/createSimpleSentryLogger are available in window.developingFeatures'
);
}
getTrackingServicesConsoleProxy.ts
import { LogLevel } from '@37bytes/logstory';
import { MiddlewareExtras, MiddlewareFunctionCallbackType } from './createLogger';
const sanitizePrefix = (prefix: unknown = '') => {
if (typeof prefix !== 'string') {
return '';
}
const startIndex = prefix.indexOf('[');
if (startIndex >= 0) {
return prefix.substring(startIndex);
}
return prefix;
};
const getTrackingServicesConsoleProxy = (
loggerName: string = 'unknown',
applyMiddleware: MiddlewareFunctionCallbackType
): Console =>
new Proxy(console, {
get(target, propKey, receiver) {
switch (propKey as LogLevel) {
case 'error':
return function (...args: unknown[]) {
const [, error, extra] = args;
applyMiddleware({
message: error,
extras: {
[MiddlewareExtras.SENTRY]: { tags: { loggerName } },
[MiddlewareExtras.GREY_LOG]: extra as ApplyMiddlewareExtras['graylogExtra']
}
});
return Reflect.get(target, propKey, receiver)(...args);
};
case 'warn':
return function (...args: unknown[]) {
const [prefix, message, extra] = arguments;
const fullMessage =
typeof message === 'string'
? sanitizePrefix(prefix).replace('%o', message)
: 'Strange warning';
applyMiddleware({
message: fullMessage,
extras: {
[MiddlewareExtras.SENTRY]: { tags: { loggerName } },
[MiddlewareExtras.GREY_LOG]: extra
}
});
return Reflect.get(target, propKey, receiver)(...args);
};
default:
return Reflect.get(target, propKey, receiver);
}
}
});
export default getTrackingServicesConsoleProxy;
logger call example
const logger = createSimpleSentryLogger('example');
logger.warn('Warn message')
logger.error(Error, { data: ['some data'] })
Issues
See the open issues for a full list of proposed features (and known issues).
version history
1.0.2
1.0.1
1.0.0