Fix DI bugs; implement general logging service
This commit is contained in:
parent
6c4696227b
commit
eddb4f1fbe
@ -133,11 +133,14 @@ class Container {
|
||||
return factory.produce(construction_args, params.reverse().all())
|
||||
}
|
||||
|
||||
make<T>(target: Instantiable<T>|DependencyKey, ...parameters: any[]): T {
|
||||
if ( isInstantiable(target) )
|
||||
make(target: DependencyKey, ...parameters: any[]) {
|
||||
if ( this.has_key(target) ) {
|
||||
return this.resolve_and_create(target, ...parameters)
|
||||
}
|
||||
else if ( typeof target !== 'string' )
|
||||
return this.produce_factory(new Factory(target), parameters)
|
||||
else
|
||||
return this.resolve_and_create(target, ...parameters)
|
||||
throw new TypeError(`Invalid or unknown make target: ${target}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,16 @@
|
||||
import { container } from '../global.ts'
|
||||
import { isInstantiable } from '../type/Instantiable.ts'
|
||||
import { Injectable } from './Injection.ts'
|
||||
|
||||
const injectable = Injectable()
|
||||
|
||||
const Service = (name?: string): ClassDecorator => {
|
||||
return (target) => {
|
||||
if ( isInstantiable(target) ) {
|
||||
if ( name ) container.register_named(name, target)
|
||||
else container.register(target)
|
||||
|
||||
injectable(target)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
15
lib/src/const/status.ts
Normal file
15
lib/src/const/status.ts
Normal file
@ -0,0 +1,15 @@
|
||||
const STATUS_STOPPED = Symbol('status stopped')
|
||||
const STATUS_STARTING = Symbol('status starting')
|
||||
const STATUS_RUNNING = Symbol('status running')
|
||||
const STATUS_STOPPING = Symbol('status stopping')
|
||||
const STATUS_ERROR = Symbol('status error')
|
||||
|
||||
const isStatus = (something: any) => [
|
||||
STATUS_STOPPED,
|
||||
STATUS_STARTING,
|
||||
STATUS_RUNNING,
|
||||
STATUS_STOPPING,
|
||||
STATUS_ERROR,
|
||||
].includes(something)
|
||||
|
||||
export { STATUS_STOPPED, STATUS_STARTING, STATUS_RUNNING, STATUS_STOPPING, STATUS_ERROR, isStatus }
|
3
lib/src/external/std.ts
vendored
Normal file
3
lib/src/external/std.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
export { serve } from 'https://deno.land/std/http/server.ts'
|
||||
export * from 'https://deno.land/std/fmt/colors.ts'
|
||||
export { config as dotenv } from 'https://deno.land/x/dotenv/mod.ts'
|
19
lib/src/lifecycle/Unit.ts
Normal file
19
lib/src/lifecycle/Unit.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { STATUS_STOPPED, isStatus } from '../const/status.ts'
|
||||
|
||||
export default abstract class LifecycleUnit {
|
||||
private _status = STATUS_STOPPED
|
||||
|
||||
public get status() {
|
||||
return this._status
|
||||
}
|
||||
|
||||
public set status(status) {
|
||||
if ( !isStatus(status) )
|
||||
throw new TypeError('Invalid unit status: '+status.description)
|
||||
|
||||
this._status = status
|
||||
}
|
||||
|
||||
public async up(): Promise<void> {};
|
||||
public async down(): Promise<void> {};
|
||||
}
|
11
lib/src/lifecycle/decorators.ts
Normal file
11
lib/src/lifecycle/decorators.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { Service } from '../../../di/src/decorator/Service.ts'
|
||||
|
||||
const service = Service()
|
||||
|
||||
const Unit = (): ClassDecorator => {
|
||||
return (target) => {
|
||||
return service(target)
|
||||
}
|
||||
}
|
||||
|
||||
export { Unit }
|
45
lib/src/service/logging/Logger.ts
Normal file
45
lib/src/service/logging/Logger.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { LogMessage, LoggingLevel } from './types.ts'
|
||||
import {make} from "../../../../di/src/global.ts";
|
||||
import {Logging} from "./Logging.ts";
|
||||
import {blue, cyan, gray, green, red, yellow} from "../../external/std.ts";
|
||||
|
||||
const isLoggerClass = (something: any): something is (typeof Logger) => {
|
||||
return something.prototype instanceof Logger
|
||||
}
|
||||
|
||||
export { isLoggerClass }
|
||||
|
||||
export default abstract class Logger {
|
||||
public abstract async write(message: LogMessage): Promise<void>;
|
||||
|
||||
public static register() {
|
||||
make(Logging).register_logger(this)
|
||||
}
|
||||
|
||||
public static remove() {
|
||||
make(Logging).remove_logger(this)
|
||||
}
|
||||
|
||||
protected format_date(date: Date): string {
|
||||
return `${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`
|
||||
}
|
||||
|
||||
protected level_display(level: LoggingLevel): string {
|
||||
switch(level) {
|
||||
case LoggingLevel.Success:
|
||||
return green('success')
|
||||
case LoggingLevel.Error:
|
||||
return red('error')
|
||||
case LoggingLevel.Warning:
|
||||
return yellow('warning')
|
||||
case LoggingLevel.Info:
|
||||
return blue('info')
|
||||
case LoggingLevel.Debug:
|
||||
return cyan('debug')
|
||||
case LoggingLevel.Verbose:
|
||||
return gray('verbose')
|
||||
case LoggingLevel.Silent:
|
||||
return gray('silent')
|
||||
}
|
||||
}
|
||||
}
|
74
lib/src/service/logging/Logging.ts
Normal file
74
lib/src/service/logging/Logging.ts
Normal file
@ -0,0 +1,74 @@
|
||||
import {LoggingLevel, LogMessage} from './types.ts'
|
||||
import Logger from './Logger.ts'
|
||||
import {Service} from '../../../../di/src/decorator/Service.ts'
|
||||
import {make} from '../../../../di/src/global.ts'
|
||||
import {isInstantiable} from '../../../../di/src/type/Instantiable.ts'
|
||||
|
||||
@Service()
|
||||
class Logging {
|
||||
private _level = LoggingLevel.Warning
|
||||
private _loggers: Logger[] = []
|
||||
|
||||
public get level() {
|
||||
return this._level
|
||||
}
|
||||
|
||||
public set level(level) {
|
||||
this._level = level
|
||||
}
|
||||
|
||||
public success(output: any, force = false) {
|
||||
this.write_log(LoggingLevel.Success, output, force)
|
||||
}
|
||||
|
||||
public error(output: any, force = false) {
|
||||
this.write_log(LoggingLevel.Error, output, force)
|
||||
}
|
||||
|
||||
public warn(output: any, force = false) {
|
||||
this.write_log(LoggingLevel.Warning, output, force)
|
||||
}
|
||||
|
||||
public info(output: any, force = false) {
|
||||
this.write_log(LoggingLevel.Info, output, force)
|
||||
}
|
||||
|
||||
public debug(output: any, force = false) {
|
||||
this.write_log(LoggingLevel.Debug, output, force)
|
||||
}
|
||||
|
||||
public verbose(output: any, force = false) {
|
||||
this.write_log(LoggingLevel.Verbose, output, force)
|
||||
}
|
||||
|
||||
protected write_log(level: LoggingLevel, output: any, force = false) {
|
||||
const message = this.build_message(level, output)
|
||||
if ( this._level >= level || force ) {
|
||||
for ( const logger of this._loggers ) {
|
||||
logger.write(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected build_message(level: LoggingLevel, output: any): LogMessage {
|
||||
return {
|
||||
level,
|
||||
output,
|
||||
date: new Date,
|
||||
}
|
||||
}
|
||||
|
||||
public register_logger(logger_class: typeof Logger) {
|
||||
if ( isInstantiable(logger_class) ) {
|
||||
const logger = make(logger_class)
|
||||
if ( !this._loggers.includes(logger) )
|
||||
this._loggers.push(logger)
|
||||
}
|
||||
}
|
||||
|
||||
public remove_logger(logger_class: typeof Logger) {
|
||||
this._loggers = this._loggers.filter(x => !(x instanceof logger_class))
|
||||
}
|
||||
}
|
||||
|
||||
export { Logging }
|
11
lib/src/service/logging/StandardLogger.ts
Normal file
11
lib/src/service/logging/StandardLogger.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import AbstractLogger from './Logger.ts'
|
||||
import { LogMessage } from './types.ts'
|
||||
import { gray } from '../../external/std.ts'
|
||||
|
||||
export default class StandardLogger extends AbstractLogger {
|
||||
public async write(message: LogMessage): Promise<void> {
|
||||
const prefix = this.level_display(message.level)
|
||||
const text = `${prefix} ${gray(this.format_date(message.date))}`
|
||||
console.log(text, message.output)
|
||||
}
|
||||
}
|
33
lib/src/service/logging/types.ts
Normal file
33
lib/src/service/logging/types.ts
Normal file
@ -0,0 +1,33 @@
|
||||
enum LoggingLevel {
|
||||
Silent = 0,
|
||||
Success = 1,
|
||||
Error = 1,
|
||||
Warning = 2,
|
||||
Info = 3,
|
||||
Debug = 4,
|
||||
Verbose = 5,
|
||||
}
|
||||
|
||||
const isLoggingLevel = (something: any): something is LoggingLevel => {
|
||||
return [
|
||||
LoggingLevel.Silent,
|
||||
LoggingLevel.Success,
|
||||
LoggingLevel.Error,
|
||||
LoggingLevel.Warning,
|
||||
LoggingLevel.Info,
|
||||
LoggingLevel.Debug,
|
||||
LoggingLevel.Verbose
|
||||
].includes(something)
|
||||
}
|
||||
|
||||
interface LogMessage {
|
||||
level: LoggingLevel,
|
||||
date: Date,
|
||||
output: any,
|
||||
}
|
||||
|
||||
const isLogMessage = (something: any): something is LogMessage => {
|
||||
return isLoggingLevel(something?.level) && something?.date instanceof Date;
|
||||
}
|
||||
|
||||
export { LoggingLevel, LogMessage, isLoggingLevel, isLogMessage }
|
30
lib/src/unit/Scaffolding.ts
Normal file
30
lib/src/unit/Scaffolding.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import LifecycleUnit from '../lifecycle/Unit.ts'
|
||||
import { Unit } from '../lifecycle/decorators.ts'
|
||||
import { dotenv } from '../external/std.ts'
|
||||
import { Logging } from '../service/logging/Logging.ts'
|
||||
import StandardLogger from '../service/logging/StandardLogger.ts'
|
||||
|
||||
@Unit()
|
||||
export default class Scaffolding extends LifecycleUnit {
|
||||
private config = {}
|
||||
|
||||
constructor(
|
||||
protected logger: Logging
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
public refresh_env() {
|
||||
this.config = dotenv()
|
||||
}
|
||||
|
||||
public setup_logging() {
|
||||
StandardLogger.register()
|
||||
this.logger.info('Logging initialized.', true)
|
||||
}
|
||||
|
||||
public async up() {
|
||||
this.setup_logging()
|
||||
this.refresh_env()
|
||||
}
|
||||
}
|
5
test.ts
Normal file
5
test.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { make, container } from "./di/src/global.ts";
|
||||
import Scaffolding from "./lib/src/unit/Scaffolding.ts";
|
||||
|
||||
const scaf = make(Scaffolding)
|
||||
scaf.up()
|
@ -1,8 +1,7 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"target": "es2017"
|
||||
"emitDecoratorMetadata": true
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user