Custom Logging
The feature described in this guide is also demonstrated in the "Custom Logging" demo.
By default, the Feature Hub uses the console for all log statements. This
behaviour can be customized by providing a custom logger.
In the following examples, pino is used as a custom logger:
import pino from 'pino';
const logger = pino();
@feature-hub/core
To provide a custom logger to the FeatureAppManager and
FeatureServiceRegistry, the integrator can set the logger option of the
createFeatureHub function:
import {createFeatureHub} from '@feature-hub/core';
const {featureAppManager} = createFeatureHub('acme:integrator', {logger});
@feature-hub/react
To provide a custom logger to the React FeatureAppLoader and React
FeatureAppContainer, the integrator can use the FeatureHubContextProvider:
import {FeatureHubContextProvider} from '@feature-hub/react';
<FeatureHubContextProvider value={{featureAppManager, logger}}>
{/* render Feature Apps here */}
</FeatureHubContextProvider>
@feature-hub/dom
To provide a custom logger to the feature-app-loader and
feature-app-container custom elements, the integrator can set the logger
option of the defineFeatureAppContainer and defineFeatureAppLoader
functions:
import {
defineFeatureAppContainer,
defineFeatureAppLoader,
} from '@feature-hub/dom';
defineFeatureAppContainer(featureAppManager, {logger});
defineFeatureAppLoader(featureAppManager, {logger});
Feature Apps & Feature Services
To provide a custom logger to Feature Apps and Feature Services, the integrator
can provide the Logger Feature Service from the
@feature-hub/logger package. It must be defined with a function
that takes the consumerId and optional consumerName of the consuming Feature
App or Feature Service, and returns a Logger
instance. This makes it possible to augment the consumer logs with the
consumerId and/or consumerName, e.g. using pino's child logger:
import {defineLogger} from '@feature-hub/logger';
const {featureAppManager} = createFeatureHub('acme:integrator', {
logger,
featureServiceDefinitions: [
defineLogger((consumerId, consumerName) =>
logger.child({consumerId, consumerName}),
),
],
});
A Feature App could then use the Logger Feature Service like this:
const myFeatureAppDefinition = {
id: 'acme:my-feature-app',
dependencies: {
featureServices: {
's2:logger': '^1.0.0',
},
},
create(env) {
const logger = env.featureServices['s2:logger'];
logger.debug('foo');
// ...
},
};
Similarly, a Feature Service could use the Logger Feature Service like this:
const myFeatureServiceDefinition = {
id: 'acme:my-feature-service',
dependencies: {
featureServices: {
's2:logger': '^1.0.0',
},
},
create(env) {
const logger = env.featureServices['s2:logger'];
logger.debug('foo');
// ...
},
};
The History Service and the Async SSR
Manager have the Logger Feature Service defined
as an optional dependency. If the integrator has provided the Logger Service,
they use it for their logging. Otherwise the console is used as a fallback.