feat: configure logger during setup

This commit is contained in:
Ruben Taelman 2020-09-22 11:31:22 +02:00 committed by Ruben Taelman
parent 09ac83caa5
commit aaa49219dc
10 changed files with 100 additions and 2 deletions

View File

@ -8,6 +8,7 @@
"files-scs:config/presets/ldp/operation-handler.json",
"files-scs:config/presets/ldp/permissions-extractor.json",
"files-scs:config/presets/ldp/request-parser.json",
"files-scs:config/presets/logging.json",
"files-scs:config/presets/setup.json",
"files-scs:config/presets/storage.json",
"files-scs:config/presets/storage_wrapper.json",

View File

@ -12,6 +12,10 @@
{
"@id": "urn:solid-server:default:variable:rootFilePath",
"@type": "Variable"
},
{
"@id": "urn:solid-server:default:variable:loggingLevel",
"@type": "Variable"
}
]
}

View File

@ -0,0 +1,12 @@
{
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
"@graph": [
{
"@id": "urn:solid-server:default:LoggerFactory",
"@type": "WinstonLoggerFactory",
"WinstonLoggerFactory:_level": {
"@id": "urn:solid-server:default:variable:loggingLevel"
}
}
]
}

View File

@ -13,6 +13,9 @@
"Setup:_aclManager": {
"@id": "urn:solid-server:default:AclManager"
},
"Setup:_loggerFactory": {
"@id": "urn:solid-server:default:LoggerFactory"
},
"Setup:_base": {
"@id": "urn:solid-server:default:variable:base"
},

View File

@ -29,6 +29,16 @@ export * from './src/ldp/http/SparqlUpdateBodyParser';
export * from './src/ldp/http/SparqlUpdatePatch';
export * from './src/ldp/http/TargetExtractor';
// Logging
export * from './src/logging/LazyLogger';
export * from './src/logging/LazyLoggerFactory';
export * from './src/logging/Logger';
export * from './src/logging/LoggerFactory';
export * from './src/logging/LogLevel';
export * from './src/logging/LogUtil';
export * from './src/logging/VoidLoggerFactory';
export * from './src/logging/WinstonLoggerFactory';
// LDP/Operations
export * from './src/ldp/operations/DeleteOperationHandler';
export * from './src/ldp/operations/GetOperationHandler';

View File

@ -3,8 +3,11 @@ import type { ReadStream, WriteStream } from 'tty';
import type { LoaderProperties } from 'componentsjs';
import { Loader } from 'componentsjs';
import yargs from 'yargs';
import { getLoggerFor } from '../logging/LogUtil';
import type { Setup } from './Setup';
const logger = getLoggerFor('CliRunner');
/**
* Generic run function for starting the server from a given config
* @param args - Command line arguments.
@ -25,6 +28,7 @@ export const runCustom = function(
.options({
port: { type: 'number', alias: 'p', default: 3000 },
config: { type: 'string', alias: 'c' },
level: { type: 'string', alias: 'l', default: 'info' },
})
.help();
@ -43,12 +47,14 @@ export const runCustom = function(
'urn:solid-server:default:variable:port': argv.port,
'urn:solid-server:default:variable:base': `http://localhost:${argv.port}/`,
'urn:solid-server:default:variable:rootFilePath': process.cwd(),
'urn:solid-server:default:variable:loggingLevel': argv.level,
},
}) as Setup;
return await setup.setup();
})().then((base: string): void => {
stdout.write(`Running at ${base}\n`);
logger.log('info', `Running at ${base}`);
}).catch((error): void => {
// This is the only time we can *not* use the logger to print error messages, as dependency injection has failed.
stderr.write(`${error}\n`);
});
};

View File

@ -1,6 +1,9 @@
import streamifyArray from 'streamify-array';
import type { AclManager } from '../authorization/AclManager';
import { RepresentationMetadata } from '../ldp/representation/RepresentationMetadata';
import { LazyLoggerFactory } from '../logging/LazyLoggerFactory';
import type { LoggerFactory } from '../logging/LoggerFactory';
import { getLoggerFor } from '../logging/LogUtil';
import type { ExpressHttpServer } from '../server/ExpressHttpServer';
import type { ResourceStore } from '../storage/ResourceStore';
import { TEXT_TURTLE } from '../util/ContentTypes';
@ -10,9 +13,11 @@ import { CONTENT_TYPE } from '../util/UriConstants';
* Invokes all logic to setup a server.
*/
export class Setup {
protected readonly logger = getLoggerFor(this);
private readonly httpServer: ExpressHttpServer;
private readonly store: ResourceStore;
private readonly aclManager: AclManager;
private readonly loggerFactory: LoggerFactory;
private readonly base: string;
private readonly port: number;
@ -20,12 +25,14 @@ export class Setup {
httpServer: ExpressHttpServer,
store: ResourceStore,
aclManager: AclManager,
loggerFactory: LoggerFactory,
base: string,
port: number,
) {
this.httpServer = httpServer;
this.store = store;
this.aclManager = aclManager;
this.loggerFactory = loggerFactory;
this.base = base;
this.port = port;
}
@ -34,6 +41,9 @@ export class Setup {
* Set up a server.
*/
public async setup(): Promise<string> {
// Configure the logger factory so that others can statically call it.
LazyLoggerFactory.getInstance().setLoggerFactory(this.loggerFactory);
// Set up acl so everything can still be done by default
// Note that this will need to be adapted to go through all the correct channels later on
const aclSetup = async(): Promise<void> => {
@ -61,6 +71,7 @@ export class Setup {
},
);
};
this.logger.log('debug', 'Setup default ACL settings');
await aclSetup();
this.httpServer.listen(this.port);

30
src/logging/LogUtil.ts Normal file
View File

@ -0,0 +1,30 @@
import { LazyLoggerFactory } from './LazyLoggerFactory';
import type { Logger } from './Logger';
/**
* Gets a logger instance for the given class instance.
*
* The returned type of logger depends on the configured {@link LoggerFactory} in {@link Setup}.
*
* The following shows a typical pattern on how to create loggers:
* ```
* class MyClass {
* protected readonly logger = getLoggerFor(this);
* }
* ```
* If no class is applicable, a logger can also be created as follows:
* ```
* const logger = getLoggerFor('MyFunction');
* ```
*
* @param loggable - A class instance or a class string name.
*/
export const getLoggerFor = (loggable: string | Instance): Logger => LazyLoggerFactory.getInstance()
.createLogger(typeof loggable === 'string' ? loggable : loggable.constructor.name);
/**
* Helper interface to identify class instances.
*/
interface Instance {
constructor: { name: string };
}

View File

@ -1,5 +1,6 @@
import { Setup } from '../../../src/init/Setup';
import type { ResourceIdentifier } from '../../../src/ldp/representation/ResourceIdentifier';
import { VoidLoggerFactory } from '../../../src/logging/VoidLoggerFactory';
describe('Setup', (): void => {
let httpServer: any;
@ -16,7 +17,7 @@ describe('Setup', (): void => {
httpServer = {
listen: jest.fn(),
};
setup = new Setup(httpServer, store, aclManager, 'http://localhost:3000/', 3000);
setup = new Setup(httpServer, store, aclManager, new VoidLoggerFactory(), 'http://localhost:3000/', 3000);
});
it('starts an HTTP server.', async(): Promise<void> => {

View File

@ -0,0 +1,20 @@
import { LazyLogger } from '../../../src/logging/LazyLogger';
import { LazyLoggerFactory } from '../../../src/logging/LazyLoggerFactory';
import { getLoggerFor } from '../../../src/logging/LogUtil';
import { VoidLogger } from '../../../src/logging/VoidLogger';
describe('LogUtil', (): void => {
beforeEach(async(): Promise<void> => {
LazyLoggerFactory.getInstance().setLoggerFactory(undefined);
});
it('allows creating a lazy logger for a string label.', async(): Promise<void> => {
expect(getLoggerFor('MyLabel')).toBeInstanceOf(LazyLogger);
expect((getLoggerFor('MyLabel') as any).label).toEqual('MyLabel');
});
it('allows creating a lazy logger for a class instance.', async(): Promise<void> => {
expect(getLoggerFor(new VoidLogger())).toBeInstanceOf(LazyLogger);
expect((getLoggerFor(new VoidLogger()) as any).label).toEqual('VoidLogger');
});
});