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())
|
return factory.produce(construction_args, params.reverse().all())
|
||||||
}
|
}
|
||||||
|
|
||||||
make<T>(target: Instantiable<T>|DependencyKey, ...parameters: any[]): T {
|
make(target: DependencyKey, ...parameters: any[]) {
|
||||||
if ( isInstantiable(target) )
|
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)
|
return this.produce_factory(new Factory(target), parameters)
|
||||||
else
|
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 { container } from '../global.ts'
|
||||||
import { isInstantiable } from '../type/Instantiable.ts'
|
import { isInstantiable } from '../type/Instantiable.ts'
|
||||||
|
import { Injectable } from './Injection.ts'
|
||||||
|
|
||||||
|
const injectable = Injectable()
|
||||||
|
|
||||||
const Service = (name?: string): ClassDecorator => {
|
const Service = (name?: string): ClassDecorator => {
|
||||||
return (target) => {
|
return (target) => {
|
||||||
if ( isInstantiable(target) ) {
|
if ( isInstantiable(target) ) {
|
||||||
if ( name ) container.register_named(name, target)
|
if ( name ) container.register_named(name, target)
|
||||||
else container.register(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": {
|
"compilerOptions": {
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true
|
||||||
"target": "es2017"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user