Skip to content

Commit

Permalink
46
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Schaffer committed Mar 16, 2019
1 parent 6b2db89 commit c20f320
Show file tree
Hide file tree
Showing 59 changed files with 786 additions and 66 deletions.
2 changes: 1 addition & 1 deletion packages/dandi/common/src/disposable.ts
Expand Up @@ -49,7 +49,7 @@ export interface Disposable {

/**
* Disposes of any resources controlled by the instance
* @param reason
* @param reason A brief description of why the object is being disposed
*/
dispose(reason: string): void | Promise<void>
}
Expand Down
2 changes: 1 addition & 1 deletion packages/dandi/core/index.ts
Expand Up @@ -40,7 +40,7 @@ export * from './src/module'
export * from './src/module-builder'
export * from './src/native-now'
export * from './src/noop-logger'
export * from './src/now'
export * from './src/now-fn'
export * from './src/on-config'
export * from './src/opinionated-token'
export * from './src/optional-decorator'
Expand Down
2 changes: 1 addition & 1 deletion packages/dandi/core/logging/index.ts
Expand Up @@ -3,7 +3,7 @@ export * from './src/console.log-listener.config'
export * from './src/console.log-listener.config-default'
export * from './src/console.log-listener.config-pretty'
export * from './src/contextual.logger'
export * from './src/logger.config'
export * from './src/logger-config'
export * from './src/log-listener'
export * from './src/log-stream-subject'
export * from './src/logging.module'
Expand Up @@ -10,14 +10,33 @@ import {
TagFormatOptions,
} from './console.log-listener.config'

/**
* @internal
* @ignore
*/
export const DEFAULT_CONTEXT_TAG: ConsoleLogListenerFormatter = (entry: ConsoleLogListenerEntryInfo): string => entry.contextName

/**
* @internal
* @ignore
*/
export const DEFAULT_LEVEL_TAG: ConsoleLogListenerFormatter = (entry: ConsoleLogListenerEntryInfo): string => entry.level.toLocaleUpperCase().padEnd(entry.levelTagHighWater, ' ')

/**
* @internal
* @ignore
*/
export const DEFAULT_TIMESTAMP_FORMATTER: ConsoleLogListenerFormatter = (entry: ConsoleLogListenerEntryInfo): string => entry.ts ? entry.ts.toString() : undefined
const DEFAULT_TAG_PART_ORDER: (keyof LogCallOptions)[] = [
'level',
'timestamp',
'context',
]

/**
* @internal
* @ignore
*/
export const DEFAULT_TAG_FORMATTER = (tagInfo: LogEntryTagInfo): string => {
if (!tagInfo.partOrder.find(part => !!tagInfo[part])) {
return undefined
Expand Down Expand Up @@ -56,6 +75,10 @@ const DEFAULT_TAG_FORMAT_OPTIONS: TagFormatOptions = {
partOrder: DEFAULT_TAG_PART_ORDER,
}

/**
* @internal
* @ignore
*/
export const DEFAULT_LOGGING_CONFIG: ConsoleLogListenerConfig = {
contextTag: false,
levelTag: DEFAULT_LEVEL_TAG,
Expand All @@ -64,4 +87,7 @@ export const DEFAULT_LOGGING_CONFIG: ConsoleLogListenerConfig = {
tag: DEFAULT_TAG_FORMAT_OPTIONS,
}

/**
* A [[ConsoleLogListenerConfigProvider]] that defines basic [[LogEntry]] formatting for the console
*/
export const DefaultLogging: ConsoleLogListenerConfigProvider = consoleLogListenerConfigProvider(DEFAULT_LOGGING_CONFIG)
Expand Up @@ -8,10 +8,17 @@ import {
DefaultLogging,
} from './console.log-listener.config-default'

/**
* @internal
* @ignore
*/
export const PRETTY_LOGGING_CONFIG: ConsoleLogListenerConfig = {
contextTag: DEFAULT_CONTEXT_TAG,
levelTag: DEFAULT_LEVEL_TAG,
timestampTag: 'yyyy/MM/dd hh:mm:ss.u a',
}

/**
* A [[ConsoleLogListenerConfigProvider]] that defines some nicer looking [[LogEntry]] formatting for the console
*/
export const PrettyLogging: ConsoleLogListenerConfigProvider = DefaultLogging.clone().set(PRETTY_LOGGING_CONFIG)
24 changes: 22 additions & 2 deletions packages/dandi/core/logging/src/console.log-listener.config.ts
Expand Up @@ -2,16 +2,30 @@ import { cloneObject } from '@dandi/common'
import { LogCallOptions, LogEntry, LogLevel, ValueProvider } from '@dandi/core'
import { DateTimeFormatOptions } from 'luxon'

import { localOpinionatedToken } from './local.token'
import { localOpinionatedToken } from './local-token'

/**
* Additional metadata used for displaying a [[LogEntry]] in the console.
*/
export interface ConsoleLogListenerEntryInfo extends LogEntry {
levelTagHighWater: number
tagHighWater: number
contextName: string
}

/**
* A function that takes a [[ConsoleLogListenerEntryInfo]] object and returns a `string`.
*/
export type ConsoleLogListenerFormatter = (entryInfo: ConsoleLogListenerEntryInfo) => string

/**
* A function that generates a string or array of strings representing the "message" portion of a [[LogEntry]].
*/
export type ConsoleLogListenerMessageFormatter = (entryInfo: ConsoleLogListenerEntryInfo) => string | string[]

/**
* An object containing formatted sections of a [[LogEntry]] tag, as well as metadata and configuration data
*/
export interface LogEntryTagInfo {
partOrder: (keyof LogCallOptions)[]
context: string
Expand All @@ -24,6 +38,9 @@ export interface LogEntryTagInfo {
tagHighWater: number
}

/**
* Defines configuration options for formatting the tag portion of a [[LogEntry]]
*/
export interface TagFormatOptions {
partSeparator?: string
partOrder?: (keyof LogCallOptions)[]
Expand All @@ -43,7 +60,7 @@ export interface ConsoleLogListenerOptions {
}

export interface ConsoleLogListenerConfig extends ConsoleLogListenerOptions {
levelOptions?: { [key in keyof LogLevel]?: ConsoleLogListenerOptions }
levelOptions?: { [TKey in keyof LogLevel]?: ConsoleLogListenerOptions }
filter?: LogLevel
}

Expand All @@ -55,6 +72,9 @@ export function consoleLogListenerConfigProvider(config: ConsoleLogListenerConfi
return new ConsoleLogListenerConfigProvider(config)
}

/**
* A helper class for creating [[ConsoleLogListenerConfig]] objects.
*/
export class ConsoleLogListenerConfigProvider implements ValueProvider<ConsoleLogListenerConfig> {

private readonly config: ConsoleLogListenerConfig
Expand Down
7 changes: 5 additions & 2 deletions packages/dandi/core/logging/src/console.log-listener.ts
Expand Up @@ -35,6 +35,9 @@ function coalesceByDefined<T>(a: T, b: T): T {
return typeof a === 'undefined' ? b : a
}

/**
* A [[LogListener]] implementation that formats [[LogEntry]] objects to be displayed on the console.
*/
@Injectable(LogListener, Singleton)
export class ConsoleLogListener implements LogListener {

Expand Down Expand Up @@ -82,7 +85,7 @@ export class ConsoleLogListener implements LogListener {
console[entry.level](tag, ...entry.args)
}

private getLongestAllowedLevelTag() {
private getLongestAllowedLevelTag(): number {
const allowedLevels: LogLevel[] =
Object.keys(LogLevel)
.filter((level: LogLevel) => !this.isFiltered(level))
Expand Down Expand Up @@ -150,7 +153,7 @@ export class ConsoleLogListener implements LogListener {
return formatter(entryInfo)
}

private getContextName(context: InjectionContext) {
private getContextName(context: InjectionContext): string {
return getInjectionContextName(context)
}

Expand Down
3 changes: 1 addition & 2 deletions packages/dandi/core/logging/src/contextual.logger.ts
Expand Up @@ -8,7 +8,6 @@ import {
LoggerMethod,
LogLevel,
LogStream,
Now,
NowFn,
} from '@dandi/core'

Expand All @@ -34,7 +33,7 @@ export class ContextualLogger implements Logger {
constructor(
@Inject(LogStream) private stream: LogStream,
@Inject(InjectionContext) private context: InjectionContext,
@Inject(Now) private now: NowFn,
@Inject(NowFn) private now: NowFn,
) {}

private log(level: LogLevel, options: LogCallOptions, ...args: any[]): void {
Expand Down
@@ -1,10 +1,23 @@
import { InjectionOptions, InjectionToken, OpinionatedToken, SymbolToken } from '@dandi/core'

/**
* @internal
* @ignore
*/
export const PKG = '@dandi/core/logging'

/**
* @internal
* @ignore
*/
export function localSymbolToken<T>(target: string): InjectionToken<T> {
return SymbolToken.local<T>(PKG, target)
}

/**
* @internal
* @ignore
*/
export function localOpinionatedToken<T>(target: string, options: InjectionOptions): InjectionToken<T> {
return OpinionatedToken.local<T>(PKG, target, options)
}
8 changes: 8 additions & 0 deletions packages/dandi/core/logging/src/log-level-filter.ts
Expand Up @@ -4,13 +4,21 @@ const LOG_LEVEL_WARN = level++
const LOG_LEVEL_INFO = level++
const LOG_LEVEL_DEBUG = level++

/**
* @internal
* @ignore
*/
export enum LogLevelValue {
error = 1 << LOG_LEVEL_ERROR,
warn = 1 << LOG_LEVEL_WARN,
info = 1 << LOG_LEVEL_INFO,
debug = 1 << LOG_LEVEL_DEBUG,
}

/**
* @internal
* @ignore
*/
export enum LogLevelFilter {
error = ~(~1 << LOG_LEVEL_ERROR),
warn = ~(~1 << LOG_LEVEL_WARN),
Expand Down
2 changes: 1 addition & 1 deletion packages/dandi/core/logging/src/log-listener.ts
@@ -1,6 +1,6 @@
import { InjectionToken, LogEntry } from '@dandi/core'

import { localOpinionatedToken } from './local.token'
import { localOpinionatedToken } from './local-token'

export interface LogListener {
log(entry: LogEntry): void
Expand Down
3 changes: 3 additions & 0 deletions packages/dandi/core/logging/src/log-stream-subject.ts
@@ -1,6 +1,9 @@
import { Injectable, LogEntry, LogStream } from '@dandi/core'
import { Subject } from 'rxjs'

/**
* An implementation of [[LogStream]] based on a `Subject` from `rxjs`
*/
@Injectable(LogStream)
export class LogStreamSubject extends Subject<LogEntry> implements LogStream {

Expand Down
Expand Up @@ -6,7 +6,7 @@ import { createStubInstance } from 'sinon'

import { isFactoryProvider } from '../../src/provider-util'

import { LoggerConfig } from './logger.config'
import { LoggerConfig } from './logger-config'

describe('LoggerConfig', function() {

Expand Down
Expand Up @@ -3,6 +3,10 @@ import { OnConfigInternal } from '@dandi/core/src/on-config-internal'

import { LogListener } from './log-listener'

/**
* @internal
* @ignore
*/
export const LoggerConfig: Provider<OnConfig> = {
provide: OnConfigInternal,
useFactory: (stream: LogStream, listeners: LogListener[]): OnConfig => (): void => {
Expand Down
Empty file.
12 changes: 10 additions & 2 deletions packages/dandi/core/logging/src/logging.module.ts
@@ -1,10 +1,14 @@
import { ModuleBuilder, Registerable } from '@dandi/core'

import { PKG } from './local.token'
import { LoggerConfig } from './logger.config'
import { PKG } from './local-token'
import { LoggerConfig } from './logger-config'
import { LogStreamSubject } from './log-stream-subject'
import { ContextualLogger } from './contextual.logger'

/**
* @internal
* @ignore
*/
export class LoggingModuleBuilder extends ModuleBuilder<LoggingModuleBuilder> {
constructor(...entries: Registerable[]) {
super(LoggingModuleBuilder, PKG, ...entries)
Expand All @@ -15,4 +19,8 @@ export class LoggingModuleBuilder extends ModuleBuilder<LoggingModuleBuilder> {
}
}

/**
* A [[Module]] containing [[ContextualLogger]], [[LogStreamSubject]], and a [[Provider]] that automatically
* subscribes any registered [[LogListener]] implementations to the [[LogStream]].
*/
export const LoggingModule = new LoggingModuleBuilder(ContextualLogger, LoggerConfig, LogStreamSubject)
10 changes: 5 additions & 5 deletions packages/dandi/core/src/dandi-application-init.ts
Expand Up @@ -12,7 +12,7 @@ import { Injector } from './injector'
import { InstanceGenerator, InstanceGeneratorFactory } from './instance-generator'
import { LogStream } from './log-stream'
import { Logger } from './logger'
import { Now, NowFn } from './now'
import { NowFn } from './now-fn'
import { Optional } from './optional-decorator'
import { OnConfig } from './on-config'
import { OnConfigInternal } from './on-config-internal'
Expand Down Expand Up @@ -99,7 +99,7 @@ export class DandiApplicationInit<TConfig extends DandiApplicationConfig> implem

public async init(
@Inject(Logger) logger: Logger,
@Inject(Now) now: NowFn,
@Inject(NowFn) now: NowFn,
@Inject(LogStream) @Optional() logStream?: LogStream,
): Promise<void> {
if (logStream) {
Expand All @@ -126,7 +126,7 @@ export class DandiApplicationInit<TConfig extends DandiApplicationConfig> implem

public async scan(
@Inject(Logger) logger: Logger,
@Inject(Now) now: NowFn,
@Inject(NowFn) now: NowFn,
@Inject(Scanner) @Optional() scanners?: Scanner[],
): Promise<void> {
if (!scanners) {
Expand All @@ -143,7 +143,7 @@ export class DandiApplicationInit<TConfig extends DandiApplicationConfig> implem

public async runConfig(
@Inject(Logger) logger: Logger,
@Inject(Now) now: NowFn,
@Inject(NowFn) now: NowFn,
@Inject(OnConfig) @Optional() configs?: OnConfig[],
): Promise<void> {
if (logger) {
Expand All @@ -163,7 +163,7 @@ export class DandiApplicationInit<TConfig extends DandiApplicationConfig> implem

public async bootstrap(
@Inject(Logger) logger,
@Inject(Now) now: NowFn,
@Inject(NowFn) now: NowFn,
@Inject(EntryPoint) @Optional() entryPoint?: EntryPoint<any>,
): Promise<void> {
logger.debug(`Application starting after ${now() - this.startTs}ms`)
Expand Down
5 changes: 0 additions & 5 deletions packages/dandi/core/src/dandi-generator.ts
Expand Up @@ -24,11 +24,6 @@ export class DandiGenerator implements InstanceGenerator {

constructor(private injector: TokenInjector) {}

/**
* Generates the object instance defined by the `resolverContext`'s target. Returns a `Promise` that resolves to
* a single instance for non-multi providers, or an array for multi providers.
* @param resolverContext A [[ResolverContext]] instance used to configure the instance and resolve any dependencies
*/
public async generateInstance<T>(resolverContext: ResolverContext<T>): Promise<T | T[]> {
const entry = resolverContext.match

Expand Down
9 changes: 9 additions & 0 deletions packages/dandi/core/src/entry-point.ts
@@ -1,7 +1,16 @@
import { InjectionToken } from './injection-token'
import { localOpinionatedToken } from './local-token'

/**
* A service that is run on application startup after the rest of DI system is configured and initialized
*/
export interface EntryPoint<T = void> {

/**
* Executes application-specific startup behavior and optionally returns a value, or a Promise that results to a value.
*
* The return value is returned by [[DandiApplication.run]]
*/
run(): T | Promise<T>
}

Expand Down
4 changes: 4 additions & 0 deletions packages/dandi/core/src/factory-util.ts
@@ -1,5 +1,9 @@
export type ObjectFactory<T> = (...args: any[]) => T | Promise<T>

/**
* @ignore
* @internal
*/
export async function getInstance<T extends object>(factory: T | Promise<T> | ObjectFactory<T>, ...args: any[]): Promise<T> {
if (typeof factory === 'function') {
return (factory as ObjectFactory<T>)(...args)
Expand Down

0 comments on commit c20f320

Please sign in to comment.