jmcdo29 / ogma Goto Github PK
View Code? Open in Web Editor NEWA monorepo for the ogma logger and related packages
Home Page: https://ogma.jaymcdoniel.dev
License: MIT License
A monorepo for the ogma logger and related packages
Home Page: https://ogma.jaymcdoniel.dev
License: MIT License
Run ac test using ogma and jest and you'll see an error of getColorDepth
is not a function. The rest of the code runs fine, but this shouldn't break unit test runs.
Make she getColorDepth
is a function before calling it, otherwise call a default method
I instantiate Ogma like this (legacy code, no nest)
public constructor() {
this.ogma = new Ogma({
logLevel: this.runsInTestMode() ? 'OFF' : 'SILLY',
color: true,
application: process.env.ENVIRONMENT,
json: this.runsOnHeroku(),
});
}
this.runsInTestMode()
is true, so log level is OFF, I expect no output. OFF = 0
Some code issues a debug log
public debug(component: string, message: string, meta: { [key: string]: unknown } = {}) {
meta.environment = process.env.ENVIRONMENT;
this.ogma.debug(`${message}`, {
context: component,
...meta,
});
}
This is being logged with debug DEBUG = 3
The log is being printed with the code below
private printMessage(message: any, options: PrintMessageOptions): void {
if (options.level < LogLevel[this.options.logLevel]) {
return;
}
let logString = '';
if (this.options.json) {
logString = this.formatJSON(message, options);
} else {
logString = this.formatStream(message, options);
}
this.options.stream.write(`${logString}\n`);
if (this.options.verbose && !this.options.json) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { context, application, correlationId, level, formattedLevel, ...meta } = options;
this.options.stream.write(this.formatStream(meta, options));
}
}
options.level < LogLevel[this.options.logLevel]
== 3 < 0
== false => it prints
OFF for me means no output. So OFF should be 8
I've been using Ogma for a while now, and today decided to add GraphQL subscriptions.
As far as I can tell, the Ogma interceptor chooses platform-express for this request and then dies because request is not defined.
[TypeError: Cannot set property 'requestId' of undefined
at GraphQLParser.setRequestId (/Users/roderik/Development/bpaas-launchpad/packages/module-strict-config/node_modules/@ogma/platform-express/lib/express-interceptor.service.js:32:23)
at DelegatorService.setRequestId (/Users/roderik/Development/bpaas-launchpad/packages/launchpad-api/node_modules/@ogma/nestjs-module/lib/interceptor/providers/delegator.service.js:27:22)
at OgmaInterceptor.intercept (/Users/roderik/Development/bpaas-launchpad/packages/launchpad-api/node_modules/@ogma/nestjs-module/lib/interceptor/ogma.interceptor.js:37:23)
at /Users/roderik/Development/bpaas-launchpad/packages/launchpad-api/node_modules/@nestjs/core/interceptors/interceptors-consumer.js:23:36
at InterceptorsConsumer.intercept (/Users/roderik/Development/bpaas-launchpad/packages/launchpad-api/node_modules/@nestjs/core/interceptors/interceptors-consumer.js:25:24)
at target (/Users/roderik/Development/bpaas-launchpad/packages/launchpad-api/node_modules/@nestjs/core/helpers/external-context-creator.js:76:60)
at /Users/roderik/Development/bpaas-launchpad/packages/launchpad-api/node_modules/@nestjs/core/helpers/external-proxy.js:9:30
at /Users/roderik/Development/bpaas-launchpad/packages/launchpad-api/node_modules/graphql/subscription/subscribe.js:177:19
at new Promise (<anonymous>)
at executeSubscription (/Users/roderik/Development/bpaas-launchpad/packages/launchpad-api/node_modules/graphql/subscription/subscribe.js:162:10)
at /Users/roderik/Development/bpaas-launchpad/packages/launchpad-api/node_modules/graphql/subscription/subscribe.js:137:9
at new Promise (<anonymous>)
at createSourceEventStream (/Users/roderik/Development/bpaas-launchpad/packages/launchpad-api/node_modules/graphql/subscription/subscribe.js:130:10)
at subscribeImpl (/Users/roderik/Development/bpaas-launchpad/packages/launchpad-api/node_modules/graphql/subscription/subscribe.js:69:23)
at subscribe (/Users/roderik/Development/bpaas-launchpad/packages/launchpad-api/node_modules/graphql/subscription/subscribe.js:32:65)
at /Users/roderik/Development/bpaas-launchpad/packages/launchpad-api/node_modules/subscriptions-transport-ws/src/server.ts:359:52]
return {
service: {
logLevel: this.isTestRun() ? 'ERROR' : 'ALL',
color: true,
application: this.get<Environments>('environment'),
json: this.runsOnHeroku(),
},
interceptor: {
http: ExpressParser,
ws: false,
gql: GraphQLParser,
rpc: false,
},
};
It should pick GraphQLParser as an interceptor
latest everything
This is a direct follow up of #535. I forgot that the cloud providers, e.g. google, sometimes do not use level but severity as the key for the level. Hence, for Staackdriver to pick up the logs, the level value must be put into the severity field.
Stackdriver does not pick up the level.
Either a config option to set the key name like a "key map" or a function that allows modification of the json before it is written would be great.
When installing and using @ogma/cli
inside of a project directory that has @nestjs/common@latest
installed, the ogma
command exits silently with a status of 1
when ran via a package manager script.
https://github.com/ohmree/ogma-cli-repro
pnpm i
pnpm ogma
echo $status
1
We should be able to install @ogma/cli
inside a project directory and use it inside a package manager script as well as being able to install it globally and using it via the direct CLI command without getting an error
@ogma/cli
: 2.1.6@ogma/nestjs-module
: 3.2.0@ogma/platform-express
: 3.0.116.13.0
jmcdo29 — Today at 9:46 AM
Ah, looks like for some reason @ogma/[email protected] has a pinned version of @nestjs/common and @nestjs/core in the dependencies when they should be peer deps. No idea how that happened, but I'll get a fix up for that later today
omri — Today at 9:46 AM
awesome, thanks!
jmcdo29 — Today at 10:04 AM
Okay, so I realized why I set it up this way. I wanted the CLI to runnable after a simple npm i -g @ogma/cli (or the yarn and pnpm equiv), so I made hard deps on @nestjs/common and @nestjs/core as nest-commander is going to require them to run. However, that creates a problem when running it inside of a project that has differing @nestjs/ packages. Let me see if I can resolve the issues in the repro and find a way to make this work as is
omri — Today at 10:05 AM
in the meanwhile, would installing the exact version of nestjs @ogma/cli uses help?
jmcdo29 — Today at 10:05 AM
Yeah, you should be able to downgrade to 8.4.0 I think.
omri — Today at 10:09 AM
eh, couldn't get that to work and it's annoying to fiddle with
i'll just wait for a fix
aaaand i got it to work
thanks 🙂
jmcdo29 — Today at 10:13 AM
What did you end up doing?
I may need to document this about the CLI
omri — Today at 10:15 AM
hard-pinned anything nestjs-related that used the same version number as @nestjs/core to "8.4.0", no caret
jmcdo29 — Today at 10:16 AM
Had a feeling that would be the "solution"
I'll fiddle with some peerDep configs and see if I can make it use the existing package and if not install the required deps
jmcdo29 — Today at 10:46 AM
Another option in the meantime is to install the @ogma/cli package globally and then use ogma as a direct command. I'll still work on fixing this, just thought I'd mention the other option
jmcdo29 — Today at 4:33 PM
All right, so definitely realized this is not near as straightforward as I initially though, because the @ogma/cli needs to be able to be installed globally as well as inside an project directory. When inside a project directory, the @ogma/cli package needs to be using peerDeps for the @nestjs/ packages, but when installed globally it should use dependencies. Very tricky to figure this out. I'll create an issue using your minimum reproduction as the repro repo and put updates there as I figure things out so we can track this better
If an Error
instance is passed to any logger method other than printError
, the printed log is an empty object {}
const { Ogma } = require('@ogma/logger');
const ogma = new Ogma();
ogma.log(new Error('I want to see this'));
The logger should log the error message and error name.
Make sure, before running typeof message === 'object'
that the message isn't an error object.
@ogma/logger version: 1.0.0
I get some peer dependency issues which I can’t resolve by myself.
When running npm i @ogma/logger@latest @ogma/nestjs-module@latest @ogma/platform-fastify@latest @ogma/platform-tcp@latest
in a new empty folder with the default package.json
(output of npm init -y
), it installed @ogma/[email protected]
(the other packages are of latest version), it completes successfully (obviously). However, when I install @ogma/[email protected]
, it fails (due to peer deps issues above). When I force it (using --force
), it completes successfully (albeit with warnings), however, any subsequent installations of any packages won’t complete unless forced.
Now, in node_modules/@ogma/platform-fastify/package.json
, I have the following:
"peerDependencies": {
"@nestjs/platform-fastify": "^9.0.0",
"@ogma/nestjs-module": "^4.0.0",
"fastify": ">=4.0.0",
"@ogma/logger": "2.3.0",
"@ogma/common": "1.1.0",
"@ogma/styler": "1.0.0"
},
however, in packages/platform-fastify/package.json
, there is no @ogma/logger
/@ogma/common
/@ogma/styler
peer dependency:
ogma/packages/platform-fastify/package.json
Lines 26 to 30 in 7b44215
Note that this could be an issues in other packages in this repository, however, I use only four packages (listed in the title of this issue and in the list of package versions).
not needed
npm init -y
.@ogma/logger/2.3.0
] npm i @ogma/logger@latest @ogma/nestjs-module@latest @ogma/platform-fastify@latest @ogma/platform-tcp@latest
npm i @ogma/[email protected] @ogma/nestjs-module@latest @ogma/platform-fastify@latest @ogma/platform-tcp@latest
npm i --force @ogma/[email protected] @ogma/nestjs-module@latest @ogma/platform-fastify@latest @ogma/platform-tcp@latest
No peer dependency issues.
@ogma/logger
: 2.4.1
;@ogma/nestjs-module
: 4.2.0
;@ogma/platform-fastify
: 4.0.0
;@ogma/platform-tcp
: 4.0.0
.19.0.0
See the logs below:
npm ERR! code ERESOLVE
npm ERR! ERESOLVE could not resolve
npm ERR!
npm ERR! While resolving: @ogma/platform-fastify@4.0.0
npm ERR! Found: @ogma/logger@2.4.1
npm ERR! node_modules/@ogma/logger
npm ERR! peer @ogma/logger@"^2.0.0" from @ogma/nestjs-module@4.1.1
npm ERR! node_modules/@ogma/nestjs-module
npm ERR! peer @ogma/nestjs-module@"^4.0.0" from @ogma/platform-fastify@4.0.0
npm ERR! node_modules/@ogma/platform-fastify
npm ERR! @ogma/platform-fastify@"4.0.0" from the root project
npm ERR! peer @ogma/nestjs-module@"^4.0.0" from @ogma/platform-tcp@4.0.0
npm ERR! node_modules/@ogma/platform-tcp
npm ERR! @ogma/platform-tcp@"4.0.0" from the root project
npm ERR! 1 more (the root project)
npm ERR! @ogma/logger@"2.4.1" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer @ogma/logger@"2.3.0" from @ogma/platform-fastify@4.0.0
npm ERR! node_modules/@ogma/platform-fastify
npm ERR! @ogma/platform-fastify@"4.0.0" from the root project
npm ERR!
npm ERR! Conflicting peer dependency: @ogma/logger@2.3.0
npm ERR! node_modules/@ogma/logger
npm ERR! peer @ogma/logger@"2.3.0" from @ogma/platform-fastify@4.0.0
npm ERR! node_modules/@ogma/platform-fastify
npm ERR! @ogma/platform-fastify@"4.0.0" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!
npm ERR! See /home/ts/.npm/eresolve-report.txt for a full report.
npm ERR! A complete log of this run can be found in:
npm ERR! /home/ts/.npm/_logs/2022-10-28T13_40_45_340Z-debug-0.log
Now that the core functionality has been re-written, it would be great to actually include Redis in the request logging.
Looking for: package under the name @ogma/platform-redis
that exports a class RedisInterceptorParser
that extends AbstractInterceptorService
from the @ogma/nestjs-module
package.
The output of this is still to be determined. Some values may need to be hard-coded
Now that the core functionality has been re-written, it would be great to actually include Socket.io in the request logging.
Looking for: package under the name @ogma/platform-socket.io
that exports a class SocketioInterceptorParser
that extends AbstractInterceptorService
from the @ogma/nestjs-module
package.
The output of this is still to be determined. Some values may need to be hard-coded
[2021-08-26T14:03:10.537Z] [ERROR] [eris] [development] [40475] [ExceptionsHandler] TypeError: Cannot set property 'requestId' of undefined
at GraphQLParser.setRequestId (/Users/roderik/Development/bpaas/node_modules/@ogma/platform-express/lib/express-interceptor.service.js:32:23)
at DelegatorService.setRequestId (/Users/roderik/Development/bpaas/node_modules/@ogma/nestjs-module/lib/interceptor/providers/delegator.service.js:27:22)
at OgmaInterceptor.intercept (/Users/roderik/Development/bpaas/node_modules/@ogma/nestjs-module/lib/interceptor/ogma.interceptor.js:40:23)
at /Users/roderik/Development/bpaas/node_modules/@nestjs/core/interceptors/interceptors-consumer.js:23:36
at InterceptorsConsumer.intercept (/Users/roderik/Development/bpaas/node_modules/@nestjs/core/interceptors/interceptors-consumer.js:25:24)
at target (/Users/roderik/Development/bpaas/node_modules/@nestjs/core/helpers/external-context-creator.js:77:60)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at /Users/roderik/Development/bpaas/node_modules/@nestjs/core/helpers/external-proxy.js:9:24
at Object.createAsyncIterator (/Users/roderik/Development/bpaas/node_modules/@nestjs/graphql/dist/utils/async-iterator.util.js:6:27)
Currently, if @OgmaLogger()
is used in any test the error Error: Expected OgmaCoreModule to be configured by at last one Module but it was not configured within 0ms
will appear in the console. While this doesn't fail the test, because it is an UnhandledPromiseRejection
it may end up failing in the future.
@Injectable()
export class AppService {
constructor(@OgmaLogger(AppService) private readonly logger: OgmaService) {}
getHello(): Record<string, string> {
this.logger.log("Say Hello!");
return { hello: "world" };
}
}
describe('AppService', () => {
let service: AppService;
beforeEach(async () => {
const modRef = await Test.createTestingModule({
providers: [
AppService,
{
provide: 'OGMA_SERVICE:AppService',
useValue: {
log: jest.fn(),
}
}
]
}).compile();
service = modRef.get(AppService);
});
it('should be defined', () => {
expect(service).toBeTruthy();
});
it('should return { hello: world }', () => {
expect(service.getHello()).toEqual({ hello: 'world' });
});
});
No errors to arise when running unit tests.
In the OgmaModule
's @Module()
metadata, imports: [OgmaCoreModule.Deferred]
is used. Because of this, and because it is in a decorator, it gets ran immediately, which means the observable there will be fired and possibly end up erroring out. It can probably be removed as the forRoot
, forRootAsync
, and forFeature
all use the imports
directly
@ogma/nestjs-module version: 0.2.0
For Tooling issues:
- Node version: 14.5.0
- Platform: MacOS
Others:
Now that the core functionality has been re-written, it would be great to actually include RabbitMQ in the request logging.
Looking for: package under the name @ogma/platform-rabbitmq
that exports a class RabbitmqInterceptorParser
that extends AbstractInterceptorService
from the @ogma/nestjs-module
package.
The output of this is still to be determined. Some values may need to be hard-coded
Now that the core functionality has been re-written, it would be great to actually include TCP in the request logging.
Looking for: package under the name @ogma/platform-tcp
that exports a class TcpInterceptorParser
that extends AbstractInterceptorService
from the @ogma/nestjs-module
package.
The output of this is still to be determined. Some values may need to be hard-coded
Add support to the Module to support calls to and from Websockets, to give a better tracking context of the request throughout the server.
A bit of a rewrite of the parsers and the delegator service itself. Now, instead of having a hard dependency on HttpInterceptorService
,WsInterceptorService
,GqlInterceptorService
, and WsInterceptorService
, the idea is to let each parser use @Parser('context-type')
and inject the DiscoveryService
, then onModuleInit
resolve all the parsers and hold them in a local map of Record<string, AbstractInterceptorParser>
. I'd like to stronger type that map, but it needs to stay at string so that context types other than just what Nest has already built can be used as well, like how necord
has a context type of discord
. Then, on request, something like const parser = this.parserMap[contextType]; parser.getSuccessContext(context)
can be called. This should be more extensible for future parsers and additions to the framework
Originally posted by tukusejssirs September 27, 2022
When we run console.log('some data:', object)
it outputs some data:
, a space and the object
in ‘JavaScript format’ (i.e. not in valid JSON format, but similar to it).
Now I’d like to use Ogma similarly, i.e. to output two or more items in one call. I understand that we cannot do it same way as we do it with console.log()
, however, could we use, e.g., an array as the first parameter of Ogma logger methods, potentially with a flag/property in the Ogma options object (you call it meta
) to make Ogma output the array items individually, rather than as an array?
I would be okay if any object/array would be output as a valid JSON.
I get the above error when running ^0.2.2
and above but not with ^0.1.0
I cannot find any breaking change about this?
The app doesn't start because of that error.
It should start.
@ogma/nestjs-module version: ^0.2.2 and above
For Tooling issues:
- Node version: v12.16.1
- Platform: Ubuntu 18.04 (WSL 2)
Others:
Break on npm install after version change
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: nest-starter@0.0.1
npm ERR! Found: @nestjs/[email protected]
npm ERR! node_modules/@nestjs/platform-socket.io
npm ERR! @nestjs/platform-socket.io@"^8.0.6" from the root project
npm ERR! peerOptional @nestjs/platform-socket.io@"^8.0.0" from @nestjs/[email protected]
npm ERR! node_modules/@nestjs/websockets
npm ERR! @nestjs/websockets@"^8.0.6" from the root project
npm ERR! peer @nestjs/websockets@"^8.0.0" from @nestjs/[email protected]
npm ERR! 2 more (@nestjs/core, @nestjs/microservices)
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer @nestjs/platform-socket.io@"^7.0.0" from @ogma/platform-socket.io@3.0.1
npm ERR! node_modules/@ogma/platform-socket.io
npm ERR! @ogma/platform-socket.io@"^3.0.1" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!
npm ERR! See /Users/zieglar/.cache/node-v14.17.5/eresolve-report.txt for a full report.
npm ERR! A complete log of this run can be found in:
npm ERR! /Users/zieglar/.cache/node-v14.17.5/_logs/2021-09-13T04_19_14_358Z-debug.log
@ogma/nestjs-module version: 3.1.0
For Tooling issues:
- Node version: 14.17.5
- Platform: Mac
Others:
I have an endpoint in my NestJS application that responds with image instead of json:
@Get('/og/:hash')
async getOpenGraphImage(@Param('hash') hash: string, @Res() response: Response): Promise<Response<Buffer>> {
const imageBuffer = await this.ogImageService.getImageBuffer(hash);
return response.setHeader('Content-Type', 'image/png').send(imageBuffer);
}
But whenever I try to hit this endpoint I see the following error in the terminal:
This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason:
Error: Cannot set headers after they are sent to the client
at new NodeError (node:internal/errors:371:5)
at ServerResponse.setHeader (node:_http_outgoing:576:11)
at ServerResponse.header (/home/goodwin/flaut-nestjs/node_modules/express/lib/response.js:776:10)
at ServerResponse.send (/home/goodwin/flaut-nestjs/node_modules/express/lib/response.js:170:12)
at ServerResponse.json (/home/goodwin/flaut-nestjs/node_modules/express/lib/response.js:267:15)
at ExpressAdapter.reply (/home/goodwin/flaut-nestjs/node_modules/@nestjs/platform-express/adapters/express-adapter.js:36:57)
at ExceptionsHandler.handleUnknownError (/home/goodwin/flaut-nestjs/node_modules/@nestjs/core/exceptions/base-exception-filter.js:38:24)
at ExceptionsHandler.catch (/home/goodwin/flaut-nestjs/node_modules/@nestjs/core/exceptions/base-exception-filter.js:17:25)
at ExceptionsHandler.next (/home/goodwin/flaut-nestjs/node_modules/@nestjs/core/exceptions/exceptions-handler.js:16:20)
at /home/goodwin/flaut-nestjs/node_modules/@nestjs/core/router/router-proxy.js:13:35
Private repo with copyrighted codebase
No response
Ogma should verify if the response has already been sent by checking out the value of res.headersSent
@ogma/nestjs-module
: 3.1.1@ogma/platform-express
: 3.0.116.13.2
No response
I have been using each
for a quite while and I noticed that I prefer using it by default (i.e. without appending {each: true}
to each log command).
Would it be possible to define the default value of each
, e.g., in the Nest module (either in OgmaModule.forRoot()
or OgmaModule.forFeature()
) and execute this.logger.info([1, 2, 3])
?
Thanks! 🙏
Originally posted by @tukusejssirs in #1381 (comment)
Not really a problem. Just a feature I think would be good to implement and I want to track this. I'd like to be able to let the ogma
CLI read input from a stream like a piped process and not just from a file
I'd like to be able to run something like nest start --watch | ogma
and have json: true
in my OgmaModule
's configuration but still see the nice dev logs.
Mention it in the docs and say it works similarly to pino's pretty cli
More flexibility in how logs are viewed, and the ability to have the same config not relying on env variables for dev and prod builds
It would be great to overwrite the log levels.
A way to overwrite the log levels for printing. The methods should stay the same, just the print would change.
Example from Pino using nestjs-pino
return LoggerModule.forRootAsync({
imports: [ConfigModule],
useFactory: (configService: ConfigService<Configuration>) => {
const severityLookup: Record<string, string> = {
default: 'DEFAULT',
silly: 'DEFAULT',
verbose: 'DEBUG',
debug: 'DEBUG',
http: 'INFO',
info: 'INFO',
warn: 'WARNING',
error: 'ERROR',
};
return {
pinoHttp: {
formatters: {
level(label, number) {
return { severity: severityLookup[label], level: number };
},
},
},
};
},
inject: [ConfigService],
});
Some cloud providers require certain log levels for their log collectors to pick it up properly. See Googles log levels as an example.
Hey,
thanks for this awesome logger, really fell in love with it!
I'm on Linux and would like to use the ogma CLI but the shebang interpreter is not the usual for Linux:
#! /bin/node
should be #!/usr/bin/env node
You can also refer to this: https://stackoverflow.com/questions/10376206/what-is-the-preferred-bash-shebang
NaN
npm install -g @ogma/cli
ogma test.log
Be able to run ogma cli on Linux.
@ogma/cli
: 2.1.516.14.0
Thanks in advance, and don't hesitate if you need more debug or help!
Cheers
Now that the core functionality has been re-written, it would be great to actually include WS in the request logging.
Looking for: package under the name @ogma/platform-ws
that exports a class WsInterceptorParser
that extends AbstractInterceptorService
from the @ogma/nestjs-module
package.
The output of this is still to be determined. Some values may need to be hard-coded
After setting WriteStream: createReadStream('info.log')
to service configuration for writing logs to the info log file, but it didn't write anything and it doesn't appear any error message
https://github.com/AyubTouba/ogma-bug-writeStream
No response
Write logs into log file
@ogma/cli: "^2.1.4",
@ogma/nestjs-module: "^3.1.0",
@ogma/platform-express: "^3.0.1",
12.22.7
No response
Reproduction repository: https://github.com/bibo5088/nest-ogma-bug
The browser correctly shows a 400 code, while ogma logs a 500 code.
Currently, the generateRequestId
method accepts no parameters and generally creates a single id based off of the time and Math.random()
.
The generateRequestId
method should accept the ExecutionContext
so that the id can be pulled off the request in the case that it's set from a middleware or guard, or if it is sent in from another application in the request header (or similar for other transports)
Just add to the README that the generateRequestId
now accepts the ExecutionContext
as a parameter.
#goal was to use ogma in nest js+graphql project
#problem I’ve got TypeError common_1.ConfigurableModuleBuilder is not a constructor
on nest js startup
ogma
logger as shown here: https://github.com/jmcdo29/ogma/tree/main/packages/nestjs-module$ yarn list | grep nestjs
├─ @liaoliaots/[email protected]
├─ @nestjs/[email protected]
├─ @nestjs/[email protected]
├─ @nestjs/[email protected]
│ ├─ @nestjs/schematics@^8.0.3
├─ @nestjs/[email protected]
├─ @nestjs/[email protected]
├─ @nestjs/[email protected]
├─ @nestjs/[email protected]
│ ├─ @nestjs/[email protected]
├─ @nestjs/[email protected]
├─ @nestjs/[email protected]
├─ @nestjs/[email protected]
├─ @nestjs/[email protected]
├─ @nestjs/[email protected]
├─ @nestjs/[email protected]
├─ @ogma/[email protected]
$ y list | grep ogma
├─ @ogma/[email protected]
├─ @ogma/[email protected]
├─ @ogma/[email protected]
TypeError: common_1.ConfigurableModuleBuilder is not a constructor
at Object. (/home/dmitriy/workspace/oneclick/looky-api-gateway/node_modules/@ogma/nestjs-module/src/ogma-core.module-definition.js:6:6)
at Module._compile (node:internal/modules/cjs/loader:1105:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
at Module.load (node:internal/modules/cjs/loader:981:32)
at Function.Module._load (node:internal/modules/cjs/loader:827:12)
at Module.require (node:internal/modules/cjs/loader:1005:19)
at require (node:internal/modules/cjs/helpers:102:18)
at Object. (/home/dmitriy/workspace/oneclick/looky-api-gateway/node_modules/@ogma/nestjs-module/src/ogma.constants.js:5:39)
at Module._compile (node:internal/modules/cjs/loader:1105:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
OAuth usually passes things like hmac
and code
as query params. These get logged as is, as the HttpInterceptorService.getCallPoint()
does nothing but return request.originalUrl
.
I would like to apply masks to query strings as well.
No response
Increase security when logging HTTP requests.
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These updates are currently rate-limited. Click on a checkbox below to force their creation now.
@types/react
, @types/react-dom
)These updates have all been created already. Click a checkbox below to force a retry/rebase of any.
react
, react-dom
)These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.
@apollo/gateway
, apollo-server-express
)@graphql-tools/schema
, @graphql-tools/utils
)socket.io
, socket.io-client
)@graphql-tools/schema
, @graphql-tools/utils
)docker-compose.yml
.github/workflows/ci.yml
nrwl/ci v0.13.0
actions/checkout v3
actions/setup-node v3
actions/checkout v3
github/codeql-action v2
github/codeql-action v2
github/codeql-action v2
pascalgn/automerge-action v0.15.6
nrwl/ci v0.13.0
.github/workflows/docs-deploy.yml
jitterbit/get-changed-files v1
actions/checkout v3
actions/setup-node v3
actions/upload-pages-artifact v1
actions/deploy-pages v2
.github/workflows/release.yml
nrwl/nx-set-shas v3
changesets/action v1
benchmarks/bench/package.json
benchmarks/interceptor/package.json
benchmarks/logger/package.json
package.json
@algolia/client-search ^4.14.2
@apollo/gateway 2.4.7
@apollo/server 4.7.1
@astrojs/preact ^2.0.0
@astrojs/react ^2.0.0
@astrojs/sitemap ^1.2.2
@changesets/cli ^2.25.2
@commitlint/cli 17.6.5
@commitlint/config-conventional 17.6.5
@docsearch/css ^3.3.0
@docsearch/react ^3.3.0
@graphql-tools/schema 9.0.18
@graphql-tools/utils ^9.0.0
@grpc/grpc-js ^1.7.3
@grpc/proto-loader 0.7.6
@mdx-js/react 2.3.0
@mercuriusjs/gateway ^1.2.0
@nestjs/apollo ^12.0.1
@nestjs/common 10.0.0
@nestjs/core 10.0.0
@nestjs/graphql ^12.0.1
@nestjs/mercurius ^12.0.1
@nestjs/microservices ^10.0.0
@nestjs/platform-express 10.0.0
@nestjs/platform-fastify ^10.0.0
@nestjs/platform-socket.io ^10.0.0
@nestjs/platform-ws ^10.0.0
@nestjs/testing ^10.0.0
@nestjs/websockets ^10.0.0
@nrwl/devkit 16.3.2
@nrwl/eslint-plugin-nx 16.3.2
@nrwl/js 16.3.2
@nrwl/linter 16.3.2
@nrwl/nest 16.3.2
@nrwl/node 16.3.2
@nrwl/nx-cloud 16.0.5
@nrwl/workspace 16.3.2
@swc/cli ^0.1.62
@swc/core ^1.3.51
@swc/register ^0.1.10
@types/benchmark ^2.1.2
@types/bunyan ^1.8.8
@types/express ^4.17.14
@types/express-serve-static-core ^4.17.31
@types/morgan ^1.9.3
@types/node 18.16.18
@types/react ^18.0.25
@types/react-dom ^18.0.8
@types/ws 8.5.4
@typescript-eslint/eslint-plugin 5.59.11
@typescript-eslint/parser 5.59.11
amqp-connection-manager 4.1.13
amqplib 0.10.3
apollo-server-express 3.11.1
apollo-server-fastify 3.12.0
astro ^2.0.0
axios ~1.4.0
benchmark ^2.1.4
bunyan ^1.8.15
c8 ^8.0.0
class-transformer 0.5.1
class-validator ^0.14.0
clsx ^1.2.1
conventional-changelog-cli ^3.0.0
cz-conventional-changelog ^3.3.0
eslint 8.43.0
eslint-config-prettier ^8.5.0
eslint-plugin-prettier ^4.2.1
eslint-plugin-simple-import-sort 10.0.0
express ^4.18.2
fast-safe-stringify ^2.1.1
fastify 4.18.0
graphql ^16.6.0
hanbi ^1.0.1
hastscript ^7.1.0
husky ^8.0.1
ioredis ^5.2.4
kafkajs 2.2.4
lcov-result-merger ^4.0.0
lint-staged 13.2.2
mercurius 13.0.0
module-alias ^2.2.2
morgan ^1.10.0
mqtt ^4.3.7
nats ^2.8.0
nest-commander ^3.9.0
nest-commander-testing 3.2.0
nx 16.3.2
nx-cloud ^16.0.5
nx-uvu ^1.3.0
on-exit-leak-free ^2.1.0
pactum ^3.2.3
pino 8.14.1
preact ^10.11.2
prettier ^2.7.1
react ^17.0.2
react-dom ^17.0.2
redis ^4.0.0
reflect-metadata ^0.1.13
remark-directive ^2.0.1
rimraf ^5.0.0
rxjs ^7.8.0
socket.io 4.6.1
socket.io-client 4.6.1
sonic-boom ^3.2.1
tree-kill ^1.2.2
ts-morph 18.0.0
ts-node ^10.9.1
tsconfig-paths ^4.0.0
typescript 5.1.3
unist-util-visit ^4.1.1
url-loader ^4.1.1
uvu ^0.5.6
winston ^3.8.2
ws 8.13.0
node >=10
apollo-cache-control 0.15.0
axios ~1.4.0
packages/cli/package.json
@nestjs/common ^10.0.0
@nestjs/core ^10.0.0
nest-commander 3.9.0
reflect-metadata 0.1.13
node >=10
packages/common/package.json
packages/logger/package.json
fast-safe-stringify 2.1.1
on-exit-leak-free ^2.1.0
sonic-boom ^3.2.1
node >=10
packages/nestjs-module/package.json
@nestjs/common ^9.0.0 || ^10.0.0
@nestjs/core ^9.0.0 || ^10.0.0
reflect-metadata ^0.1.0
rxjs ^7.0.0
packages/platform-express/package.json
@nestjs/platform-express ^9.0.0 || ^10.0.0
packages/platform-fastify/package.json
@nestjs/platform-fastify ^9.0.0 || ^10.0.0
fastify >=4.0.0
packages/platform-graphql-fastify/package.json
@nestjs/graphql ^10.0.0 || ^11.0.0 || ^12.0.0
packages/platform-graphql/package.json
@nestjs/graphql ^10.0.0 || ^11.0.0 || ^12.0.0
packages/platform-grpc/package.json
@nestjs/microservices ^9.0.0 || ^10.0.0
@grpc/grpc-js ^1.7.3
packages/platform-kafka/package.json
@nestjs/microservices ^9.0.0 || ^10.0.0
kafkajs ^1.12.0 || ^2.0.0
packages/platform-mqtt/package.json
@nestjs/microservices ^9.0.0 || ^10.0.0
mqtt ^4.0.0
packages/platform-nats/package.json
@nestjs/microservices ^9.0.0 || ^10.0.0
nats ^1.4.0 || ^2.0.0
packages/platform-rabbitmq/package.json
@nestjs/microservices ^9.0.0 || ^10.0.0
amqp-connection-manager ^3.2.0 || ^4.0.0
amqplib ^0.5.0 || ^0.8.0 || ^0.10.0
packages/platform-redis/package.json
@nestjs/microservices ^9.0.0 || ^10.0.0
redis ^3.0.0 || ^4.0.0
packages/platform-socket.io/package.json
@nestjs/platform-socket.io ^9.0.0 || ^10.0.0
@nestjs/websockets ^9.0.0 || ^10.0.0
socket.io ^4.0.0
packages/platform-tcp/package.json
@nestjs/microservices ^9.0.0 || ^10.0.0
packages/platform-ws/package.json
@nestjs/platform-ws ^9.0.0 || ^10.0.0
@nestjs/websockets ^9.0.0 || ^10.0.0
ws ^7.4.2 || ^8.0.0
packages/styler/package.json
@ogma/common ^1.1.1
Now that the core functionality has been re-written, it would be great to actually include Kafka in the request logging.
Looking for: package under the name @ogma/platform-kafka
that exports a class KafkaInterceptorParser
that extends AbstractInterceptorService
from the @ogma/nestjs-module
package.
The output of this is still to be determined. Some values may need to be hard-coded
Now that the core functionality has been re-written, it would be great to actually include MQTT in the request logging.
Looking for: package under the name @ogma/platform-mqtt
that exports a class MqttInterceptorParser
that extends AbstractInterceptorService
from the @ogma/nestjs-module
package.
The output of this is still to be determined. Some values may need to be hard-coded
After setting up the Ogma logger together with the GraphQL Parser, the request and request id is not being registered. I also tested the HTTP which is also not working.
OgmaModule.forRoot({
service: {
color: true,
json: false,
application: 'Backend',
},
interceptor: {
http: ExpressParser,
ws: false,
gql: GraphQLParser,
rpc: false,
},
}),
GraphQLModule.forRoot({
autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
playground: config.graphql.playground,
debug: config.graphql.debug,
// We pass in context here so we can access res in GraphQL and make redirects etc.
context: ({ req, res }) => ({ req, res }),
cors: {
origin: config.security.cors,
credentials: true,
},
}),
@Module({
imports: [
OgmaModule.forFeature(MyService, { addRequestId: true }),
],
providers: [MyService],
})
export class MyModule{}
@Injectable()
export class MyService {
constructor(
@OgmaLoggerRequestScoped(MyService) private readonly logger: OgmaService,
) {}
I would expect the request and request id would be attached to the logging event. It seems like the GraphQl/HTTP events are not registered at all.
@ogma/nestjs-module version: 1.0.0
For Tooling issues:
- Node version: 14.15.4
- Platform: Windows with Ubuntu 20.04 WSL 2.0
Others:
Add support to the Module to support calls to and from Microservice, to give a better tracking context of the request throughout the server.
Ogma Cli Raised an exception if there's an empty line on the log file:
Logfile I tested with : ogma-log
Exception message : `(node:513124) UnhandledPromiseRejectionWarning: Error: The log file provided is not in Ogma format. Please try another log file.
at OgmaCommand.runForFile (/usr/lib/node_modules/@ogma/cli/src/ogma.command.js:67:19)
at async OgmaCommand.run (/usr/lib/node_modules/@ogma/cli/src/ogma.command.js:41:13)
at async Command.parseAsync (/usr/lib/node_modules/@ogma/cli/node_modules/commander/lib/command.js:904:5)
at async CommandRunnerService.run (/usr/lib/node_modules/@ogma/cli/node_modules/nest-commander/src/command-runner.service.js:103:9)
at async Function.runApplication (/usr/lib/node_modules/@ogma/cli/node_modules/nest-commander/src/command.factory.js:29:9)
at async Function.run (/usr/lib/node_modules/@ogma/cli/node_modules/nest-commander/src/command.factory.js:11:21)
at async bootstrap (/usr/lib/node_modules/@ogma/cli/src/main.js:7:5)
(node:513124) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:513124) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
`
https://gist.github.com/AyubTouba/113c5ea62829940ac941abf2c0704f25
No response
Ogma Cli should ignore any empty line on the logfile
@ogma/cli
: "^2.1.4",@ogma/nestjs-module
: "^3.1.0",@ogma/platform-express
: "^3.0.1",12.22.7
No response
In our application, we have a lot of context which is relevant for our logs.
e.g.
In general, correlation ids and useful metadata you can explorer in a log viewer.
Currently, there is only 1 field that could be used, the requestID, but we need more and do not want to replace the request correlation id.
In Winston, they catalog all these as "meta"
Now, for output, in json mode, it would output {...meta, ...currentfields}
while in text mode you either leave them out or print them in a block at the end of thee line.
By adding them to the json output, you can add columns and filter on these fields, see below for an example in datadog (with only the current fields available)
There is no breaking change, a single optional extra param to 'log' would be all that is required.
see above
Change .forFeature
options to an array instead of just one class.
It would be good to do just one .forFeature
to register n-th providers instead of register n-th .forFeature
I would like to pass array instead of just one class to .forFeature
We could just add possibility to pass array and just single class, because we don't want to do breaking change.
What do you think about it? It will work for you?
Missing log rotation option.
It would be great if there would be a configurable log rotation option for saving to file system
No response
keeping track of logs from different days or size
Now that the core functionality has been re-written, it would be great to actually include GraphQL in the request logging.
Looking for: package under the name @ogma/platform-graphql
that exports a class GqlInterceptorParser
that extends AbstractInterceptorService
from the @ogma/nestjs-module
package.
The output should be in the same format as the ExpressInterceptorParser
.
Now that the core functionality has been re-written, it would be great to actually include NATS in the request logging.
Looking for: package under the name @ogma/platform-nats
that exports a class NatsInterceptorParser
that extends AbstractInterceptorService
from the @ogma/nestjs-module
package.
The output of this is still to be determined. Some values may need to be hard-coded
The following sample code
@Module({
imports: [
OgmaModule.forRootAsync({
useFactory: (config: ConfigService) => ({
service: {
json: config.isProd(),
stream: {
write: (message) =>
appendFile(config.getLogFile(), message, (err) => {
if (err) {
throw err;
}
})
},
application: config.getAppName()
},
interceptor: {
http: ExpressParser,
ws: false,
gql: false,
rpc: false
}
}),
inject: [ConfigService]
})
]
})
Throws the following error:
The example should work flawlessly
To fix the errors I had to do the following:
@Module({
imports: [
OgmaModule.forRootAsync({
useFactory: (config: ConfigService) => ({
service: {
json: config.isProd(),
stream: {
write: (message: string): boolean => {
appendFile(config.getLogFile(), message, (err) => {
if (err) {
throw err;
}
})
return true
}
},
application: config.getAppName()
},
interceptor: {
http: ExpressParser,
ws: false,
gql: false,
rpc: false
}
}),
inject: [ConfigService]
})
]
})
@ogma/nestjs-module": "^0.3.0"
@ogma/platform-express": "^0.3.0
For Tooling issues:
- Node version: v12.11.1
- Platform: Linux xps 5.0.0-1068-oem-osp1 #73-Ubuntu
Others:
using npm
Now that the core functionality has been re-written, it would be great to actually include gRPC in the request logging.
Looking for: package under the name @ogma/platform-grpc
that exports a class GrpcInterceptorParser
that extends AbstractInterceptorService
from the @ogma/nestjs-module
package.
The output of this is still to be determined. Some values may need to be hard-coded
Now that the core functionality has been re-written, it would be great to actually include GraphQL in the request logging.
Looking for: package under the name @ogma/platform-graphql-fastify
that exports a class GqlFastifyInterceptorParser
that extends AbstractInterceptorService
from the @ogma/nestjs-module
package.
The output should be in the same format as the FastifyInterceptorParser
.
Re-write the types to be FastifyRequestLike
and ExpressRequestLike
so that there are no hard dependencies on fastify
or @types/express
package.
Allow for OgmaService to be transient-like scope using different injection tokens determined from forFeature
and add in an @OgmaLogger()
decorator that will create the correct injection token for that class. This will allow for easier use of the module and make for a better experience overall
As #9 is already a breaking change, might as well make things easier for the every day developer as well by masking the forRoot(OgmaModule, options)
functionality behind a core module that sits in the background so that all is needed is OgmaModule.forRoot(options)
or OgmaModule.forRoorAsync(asyncOptions)
. This should be easy enough to implement for anyone who wants to manage it.
Our applications outputs a huge amount of logs, a selection here:
:41:54.327Z] [gaia] [development] 54068 [ListUsersWorker][INFO] | Starting ListUsersWorker
[2020-10-26T09:41:54.330Z] [gaia] [development] 54068 [user_list_all][SILLY]| Listening to queue: rpc_request_user_list_all
[2020-10-26T09:41:54.345Z] [gaia] [development] 54068 [RequestJwtTokenWorker][INFO] | Starting RequestJwtTokenWorker
[2020-10-26T09:41:54.349Z] [gaia] [development] 54068 [jwt_token_request][SILLY]| Listening to queue: rpc_request_jwt_token_request
[2020-10-26T09:41:54.362Z] [gaia] [development] 54068 [RevokeUserAccessWorker][INFO] | Starting RevokeUserAccessWorker
[2020-10-26T09:41:54.364Z] [gaia] [development] 54068 [deployment_user_revoke][SILLY]| Listening to queue: rpc_request_deployment_user_revoke
[2020-10-26T09:41:54.371Z] [gaia] [development] 54068 [TestWorker][INFO] | Starting TestWorker
[2020-10-26T09:41:54.373Z] [gaia] [development] 54068 [test_worker][SILLY]| Listening to queue: rpc_request_test_worker
[2020-10-26T09:41:54.379Z] [gaia] [development] 54068 [UpdateInternalWorker][INFO] | Starting UpdateInternalWorker
[2020-10-26T09:41:54.381Z] [gaia] [development] 54068 [user_update_internal][SILLY]| Listening to queue: rpc_request_user_update_internal
[2020-10-26T09:41:54.393Z] [gaia] [development] 54068 [UpdatePermissionsWorker][INFO] | Starting UpdatePermissionsWorker
[2020-10-26T09:41:54.395Z] [gaia] [development] 54068 [user_update_permissions][SILLY]| Listening to queue: rpc_request_user_update_permissions
[2020-10-26T09:41:54.407Z] [gaia] [development] 54068 [UpdatePlanWorker][INFO] | Starting UpdatePlanWorker
[2020-10-26T09:41:54.410Z] [gaia] [development] 54068 [user_update_plan][SILLY]| Listening to queue: rpc_request_user_update_plan
[2020-10-26T09:41:54.416Z] [gaia] [development] 54068 [InternalCosts][INFO] | Starting InternalCosts
[2020-10-26T09:41:54.418Z] [gaia] [development] 54068 [billing_internal_costs][SILLY]| Listening to queue: rpc_request_billing_internal_costs
[2020-10-26T09:41:54.436Z] [gaia] [development] 54068 [ListAllBillingReports][INFO] | Starting ListAllBillingReports
[2020-10-26T09:41:54.438Z] [gaia] [development] 54068 [billing_reports_list_all][SILLY]| Listening to queue: rpc_request_billing_reports_list_all
[2020-10-26T09:41:54.454Z] [gaia] [development] 54068 [CheckConsortiumIdWorker][INFO] | Starting CheckConsortiumIdWorker
[2020-10-26T09:41:54.458Z] [gaia] [development] 54068 [consortium_id_check][SILLY]| Listening to queue: rpc_request_consortium_id_check
[2020-10-26T09:41:54.474Z] [gaia] [development] 54068 [CreateConsortiumWorker][INFO] | Starting CreateConsortiumWorker
[2020-10-26T09:41:54.476Z] [gaia] [development] 54068 [consortium_create][SILLY]| Listening to queue: rpc_request_consortium_create
[2020-10-26T09:41:54.505Z] [gaia] [development] 54068 [DeleteConsortiumWorker][INFO] | Starting DeleteConsortiumWorker
[2020-10-26T09:41:54.507Z] [gaia] [development] 54068 [consortium_delete][SILLY]| Listening to queue: rpc_request_consortium_delete
[2020-10-26T09:41:54.513Z] [gaia] [development] 54068 [GetConsortiumAuditlogWorker][INFO] | Starting GetConsortiumAuditlogWorker
[2020-10-26T09:41:54.516Z] [gaia] [development] 54068 [consortium_auditlog][SILLY]| Listening to queue: rpc_request_consortium_auditlog
[2020-10-26T09:41:54.522Z] [gaia] [development] 54068 [GetConsortiumWorker][INFO] | Starting GetConsortiumWorker
[2020-10-26T09:41:54.524Z] [gaia] [development] 54068 [consortium_retrieve][SILLY]| Listening to queue: rpc_request_consortium_retrieve
[2020-10-26T09:41:54.533Z] [gaia] [development] 54068 [GetConsortiumPermissionWorker][INFO] | Starting GetConsortiumPermissionWorker
[2020-10-26T09:41:54.535Z] [gaia] [development] 54068 [consortium_list_permissions][SILLY]| Listening to queue: rpc_request_consortium_list_permissions
[2020-10-26T09:41:54.542Z] [gaia] [development] 54068 [GetConsortiumUsersWorker][INFO] | Starting GetConsortiumUsersWorker
[2020-10-26T09:41:54.544Z] [gaia] [development] 54068 [consortium_list_users][SILLY]| Listening to queue: rpc_request_consortium_list_users
[2020-10-26T09:41:54.581Z] [gaia] [development] 54068 [InstallConsortiumContractWorker][INFO] | Starting InstallConsortiumContractWorker
[2020-10-26T09:41:54.583Z] [gaia] [development] 54068 [consortium_install_contract][SILLY]| Listening to queue: rpc_request_consortium_install_contract
The text format is a bit messy and with small changes, it can look much neater
[2020-10-26T09:42:20.954Z] [gaia] [development] 54068 [SILLY] [ClusterStatisticsCron] Got metrics to calculate usage for staging-brown-d-corda
Due to the complexity of #7 and #8, and dealing with the problems that will come with trying to determine a methodology for getting the request and response objects, it will be much simpler to create an @OgmaSkip()
decorator to add to the route handler to to set metadata that tells the interceptor to skip this route. This will also allow for more fluent development than the original, middleware-esque, implementation.
It would be nice if I could have an interceptor that adds some ID to requests (see example below) and than uses that ID in the log.
Tracing. That way, if a user reports an issue they can also check the request ID that they got back from the server and then a developer can search that request ID inside the logs to easily track the request that was broken.
Example interceptor for adding request IDs:
import { Request, Response } from 'express';
import { v4 as uuidv4 } from 'uuid';
import { REQUEST_ID_TOKEN_HEADER } from '../constants';
export function RequestIdMiddleware(
request: Request,
response: Response,
next: Function
): void {
if (!request.headers[REQUEST_ID_TOKEN_HEADER]) {
request.headers[REQUEST_ID_TOKEN_HEADER] = uuidv4();
}
response.set(
REQUEST_ID_TOKEN_HEADER,
request.headers[REQUEST_ID_TOKEN_HEADER]
);
next();
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.