git clone https://github.com/pinojs/pinojs
cd pinojs
npm install
npm start
pinojs / pino Goto Github PK
View Code? Open in Web Editor NEW๐ฒ super fast, all natural json logger
Home Page: http://getpino.io
License: MIT License
๐ฒ super fast, all natural json logger
Home Page: http://getpino.io
License: MIT License
Sometimes we want to avoid logging sensitive information, post processing isn't ideal for this case so it must be done in process.
We can achieve this with a serialiser generator, which should be a separate module
Once created we can add a section to the readme about handling sensitive info
hi,
from what i see, if a field has the value of undefined that key won't be logged;
https://github.com/mcollina/pino/blob/master/pino.js#L240
is this intended purpose?
sometimes it will be helpfull to see that the value of a variable is undefined so you know where to start debugging;
May be we can add a transport or extend pino-socket
to use it with MongoDB which will be a brilliant?
Thanks
Given the result of #105, should a pino-interface
module be created that is literally nothing more than?:
'use strict'
function noop () {}
module.exports = {
fatal: noop,
error: noop,
warn: noop,
info: noop,
debug: noop,
trace: noop,
flush: noop,
child: noop
}
Projects that are meant to be included in other projects, e.g. Sequelize
, would then be able to do something like:
function Instance (options) {
this.log = (options.logger) ? options.logger : require('pino-interface')
}
Instance.prototype.foo = function () {
this.log.trace('Instance.foo has been invoked')
}
I'm probably missing something, but why is the file descriptor needed in extreme mode? From what I understood it is needed to flush data before exit, does it mean that the data of the last push will be stored on a file?
Anyway if I'm logging to a writable stream what should I initialize to this.fd
? open a dummy file and get the descriptor? On the console seems to work also passing a random number (is there a way in node to safely get an unused fd other than the dummy file approach?). Is it the correct way to go or do I have to care about that file (or socket?) to retrieve the last push data in case of failures?
How is it handled when the stream is stdout?
Thanks for the help and for the great work here.
require('./')().info('%j', {hi: true})
{"pid":14050,"hostname":"MacBook-Pro-3.home","level":30,"msg":"{"hi":true}","time":1459881116335,"v":1}
that's illegal JSON (it's actually quick-formats fault), the string will need to be escaped OR we can use pino CLI to sort it out
Hi everyone!
Pino needs a nice logo. Pino means "pine", and it's an Italian word!
Pino is named after a tree (in Italian) because I wanted something related to "logs", and my house is surrounded by pines. Also @davidmarkclements liked it :)
If there is anyone that might want to contribute a nice logo, we'll be really grateful!
In Bunyan I could do
const streams = [
{
level: 'warn',
path: path.join(LOG_DIRECTORY, `${APP_NAME}-warn.log`)
},
{
level: 'error',
path: path.join(LOG_DIRECTORY, `${APP_NAME}-error.log`)
}
);
const logger = buyan.createLogger({
name: APP_NAME,
streams,
serializers: bunyan.stdSerializers
});
Looks like in pino
with the stream
argument it is only possible to write to a single stream and log level per logger instance? Is there a simple way to mimic this Bunyan behavior?
When setting the level
key to debug
and running a node script, this error shows up:
Unhandled rejection TypeError: Cannot read property 'write' of null
at LOG (/home/.../node_modules/pino/pino.js:381:9)
at Sequelize.log (/home/.../node_modules/sequelize/lib/sequelize.js:1344:21)
at Query.run (/home/.../node_modules/sequelize/lib/dialects/mysql/query.js:36:20)
at /home/.../node_modules/sequelize/lib/sequelize.js:849:20
at /home/.../node_modules/retry-as-promised/index.js:38:21
at Promise._execute (/home/.../node_modules/bluebird/js/release/debuggability.js:299:9)
at Promise._resolveFromExecutor (/home/.../node_modules/bluebird/js/release/promise.js:481:18)
at new Promise (/home/.../node_modules/bluebird/js/release/promise.js:77:14)
at retryAsPromised (/home/.../node_modules/retry-as-promised/index.js:27:10)
at /home/.../node_modules/sequelize/lib/sequelize.js:848:12
at tryCatcher (/home/.../node_modules/bluebird/js/release/util.js:16:23)
at Promise._settlePromiseFromHandler (/home/.../node_modules/bluebird/js/release/promise.js:510:31)
at Promise._settlePromise (/home/.../node_modules/bluebird/js/release/promise.js:567:18)
at Promise._settlePromise0 (/home/.../node_modules/bluebird/js/release/promise.js:612:10)
at Promise._settlePromises (/home/.../node_modules/bluebird/js/release/promise.js:691:18)
at Async._drainQueue (/home/.../node_modules/bluebird/js/release/async.js:138:16)
TypeError: Cannot read property 'write' of null
at LOG (/home/.../node_modules/pino/pino.js:381:9)
at Sequelize.log (/home/.../node_modules/sequelize/lib/sequelize.js:1344:21)
at Query.run (/home/.../node_modules/sequelize/lib/dialects/mysql/query.js:36:20)
at /home/.../node_modules/sequelize/lib/sequelize.js:849:20
at /home/.../node_modules/retry-as-promised/index.js:38:21
at Promise._execute (/home/.../node_modules/bluebird/js/release/debuggability.js:299:9)
at Promise._resolveFromExecutor (/home/.../node_modules/bluebird/js/release/promise.js:481:18)
at new Promise (/home/.../node_modules/bluebird/js/release/promise.js:77:14)
at retryAsPromised (/home/.../node_modules/retry-as-promised/index.js:27:10)
at /home/.../node_modules/sequelize/lib/sequelize.js:848:12
at tryCatcher (/home/.../node_modules/bluebird/js/release/util.js:16:23)
at Promise._settlePromiseFromHandler (/home/.../node_modules/bluebird/js/release/promise.js:510:31)
at Promise._settlePromise (/home/.../node_modules/bluebird/js/release/promise.js:567:18)
at Promise._settlePromise0 (/home/.../node_modules/bluebird/js/release/promise.js:612:10)
at Promise._settlePromises (/home/.../node_modules/bluebird/js/release/promise.js:691:18)
at Async._drainQueue (/home/.../node_modules/bluebird/js/release/async.js:138:16)
npm ERR! Linux 4.4.23-1-lts
npm ERR! argv "/home/fmm/.nvm/versions/node/v6.5.0/bin/node" "/home/fmm/.nvm/versions/node/v6.5.0/bin/npm" "run" "reset"
npm ERR! node v6.5.0
npm ERR! npm v3.10.3
npm ERR! code ELIFECYCLE
npm ERR! ...@ reset: `./libs/reset.js`
npm ERR! Exit status 255
npm ERR!
npm ERR! Failed at the ...@ reset script './libs/reset.js'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the ... package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! ./libs/reset.js
npm ERR! You can get information on how to open an issue for this project with:
npm ERR! npm bugs ...
npm ERR! Or if that isn't available, you can get their info via:
npm ERR! npm owner ls ...
npm ERR! There is likely additional logging output above.
npm ERR! Please include the following file with any support request:
npm ERR! /home/.../npm-debug.log
npm ERR! Linux 4.4.23-1-lts
npm ERR! argv "/home/fmm/.nvm/versions/node/v6.5.0/bin/node" "/home/fmm/.nvm/versions/node/v6.5.0/bin/npm" "run" "dev"
npm ERR! node v6.5.0
npm ERR! npm v3.10.3
npm ERR! code ELIFECYCLE
npm ERR! ...@ dev: `npm run reset && nodemon --watch http --watch core --watch libs --watch trade.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the ...@ dev script 'npm run reset && nodemon --watch http --watch core --watch libs --watch trade.js'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the ... package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! npm run reset && nodemon --watch http --watch core --watch libs --watch trade.js
npm ERR! You can get information on how to open an issue for this project with:
npm ERR! npm bugs ...
npm ERR! Or if that isn't available, you can get their info via:
npm ERR! npm owner ls ...
npm ERR! There is likely additional logging output above.
npm ERR! Please include the following file with any support request:
npm ERR! /home/.../npm-debug.log
The logger is being initialized like so:
const pino = require('pino')
const logger = pino({
name: 'logger',
safe: true,
timestamp: false,
level: 'debug',
serializers: {
req: pino.stdSerializers.req,
res: pino.stdSerializers.res
}
})
module.exports = exports = logger
Is this a known bug? Maybe it's related with Sequelize
, as seen in the stack trace:
...
at LOG (/home/.../node_modules/pino/pino.js:381:9)
at Sequelize.log (/home/.../node_modules/sequelize/lib/sequelize.js:1344:21)
...
Thanks
When I run my test suites (using mocha), the test report output is cluttered with log lines.
Is there a way to turn logging off without modifying my code or configuration?
I also don't see a way to disable pino programmatically, e.g. via pino.level.
What I'm looking for is a way to set the log level via an environment variable, including a way to disable logging entirely. For example:
PINO_LEVEL='disabled'
or
PINO_LEVEL='error'
I think this could be useful for testing generally, allowing me to change the logging level on an ad-hoc basis without changing code or configuration.
The README at https://www.npmjs.com/package/pino#constructor says pino([stream], [opts])
. I thought this meant we can call pino(process.stdout, {extreme: true})
. However that doesn't work, which makes sense when we look at the code:
function pino (opts, stream) {
if (opts && opts._writableState) {
stream = opts
opts = null
}
}
Should the README say pino([opts], [stream])
(reversed)?
When piping pino in the console, pino discards the lines that are not formatted exactly as it expects. Bunyan instead simply prints those line not formatted.
pull request: #95
bole is beating pino for deep object interpolation:
benchBunyanInterpolateDeep_10000: 3725.405ms
benchWinstonInterpolateDeep_10000: 14540.212ms
benchBoleInterpolateDeep_10000: 4431.450ms
benchPinoInterpolateDeep_10000: 5358.517ms
Currently it is not possible to add serializers in child loggers.
See #57 as an example of how it could be implemented.
Similar to #33 but for the ELK stack.
I see https://github.com/mcollina/pino/#pretty, but I'd expect something like this work:
var pino = require('pino')
var log = pino({
name: 'app',
safe: true
}, pino.pretty().pipe(process.stdout))
log.child({ widget: 'foo' }).info('hello')
log.child({ widget: 'bar' }).warn('hello 2')
The expectation is that this would log the 'pretty' version directly to the console. But I get an error:
/private/tmp/shit/node_modules/pino/pretty.js:111
return levelColors[value.level](levels[value.level])
^
TypeError: Cannot read property '30' of undefined
at asColoredLevel (/private/tmp/shit/node_modules/pino/pretty.js:111:23)
at DestroyableTransform.mapLine [as mapper] (/private/tmp/shit/node_modules/pino/pretty.js:91:62)
at DestroyableTransform.transform [as _transform] (/private/tmp/shit/node_modules/split2/index.js:33:21)
at DestroyableTransform.Transform._read (/private/tmp/shit/node_modules/readable-stream/lib/_stream_transform.js:159:10)
at DestroyableTransform.Transform._write (/private/tmp/shit/node_modules/readable-stream/lib/_stream_transform.js:147:83)
at doWrite (/private/tmp/shit/node_modules/readable-stream/lib/_stream_writable.js:313:64)
at writeOrBuffer (/private/tmp/shit/node_modules/readable-stream/lib/_stream_writable.js:302:5)
at DestroyableTransform.Writable.write (/private/tmp/shit/node_modules/readable-stream/lib/_stream_writable.js:241:11)
at EventEmitter.Pino.write (/private/tmp/shit/node_modules/pino/pino.js:210:17)
at EventEmitter.LOG (/private/tmp/shit/node_modules/pino/pino.js:293:10)
What am I doing wrong?
If extreme mode is enabled, and an alternate stream is supplied, data can potentially be lost on shutdown. This is possible due to the fact that the user supplied stream is likely not process.stdout
or process.stderr
and thus performs writes asynchronously. To solve this problem pino must require that user supplied streams in extreme mode are capably of synchronous writing.
This bug is being worked on in PR #84.
When used with Docker/k8s, the timestamp is added by the container, basically duplicating the timestamp. Would be great to have an option to disable the timestamp.
Proposal: A module that wraps a pino serializer (like pino-noir) into a stream that can run as a second process
Naming for this could be hard: "pino-exo" ..?
Hi, I'm working on a project where Winston & custom "transports" are used.
I would be happy to replace Winston with pino, because it looks so much better ๐
Do you have any API idea for supportings "transports" (I'll be happy to collaborate with some transports for Redis, AMQP, etc.)?
This is what Winston documentation says about transports:
https://github.com/winstonjs/winston/blob/master/docs/transports.md
I've tried to do pino -h
to list options but it doesn't work. pino -v
to print the version would also be useful.
I have some piece of code that I want only to be run if the log level is >= info. This might be akward at first but consider that I want to log the progress of some huge task that requires looking some stuff into the DB and possibly other sources:
function statProgress(npmNano, npmsNano) {
// Do nothing if loglevel is gte than info
// TODO: this won't work, pino doesn't supply getting the log level as number
if (log.levels[log.level] < log.level.stat) {
return;
}
const blacklistCount = Object.keys(config.blacklist).length;
let pending = false;
setInterval(() => {
if (pending) {
log.info('Progress stat is still being retrieved..');
return;
}
pending = true;
Promise.props({
npmDocsCount: npmNano.infoAsync().then((res) => res.doc_count - blacklistCount),
npmDesignDocsCount: npmNano.listAsync({ startkey: '_design/', endkey: '_design0' }).then((res) => res.rows.length),
npmsModulesCount: npmsNano.viewAsync('npms-analyzer', 'modules-evaluation', { reduce: true }).then((res) => res.rows[0].value),
})
.finally(() => { pending = false; })
.then((result) => {
const analysis = `${(result.npmsModulesCount / (result.npmDocsCount - result.npmDesignDocsCount) * 100).toFixed(4)}%`;
log.info({ analysis }, 'Progress stat');
}, (err) => {
log.error({ err }, 'Progress stat failed');
})
.done();
}, 15000)
.unref();
}
Obviously I don't want to be querying the DB if the loglevel is >= info. I know I can compare with strings, but I have to do 3 comparisons and is not "future" proof.
I think Pino should have its own GitHub Organization. This would provide a central place for "official" modules in the Pino ecosystem. Such modules would be things like chops
and pino-multi-stream
(since @mcollina is willing to help maintain it). Additionally, we would be able to give Pino a proper website via GitHub Pages. Given that we wouldn't want to put the website in the pino
repository, I am proposing the organization name be pinojs
.
What do you think, @mcollina @davidmarkclements ?
Should we break the pretty print out into it's own module, it seems to be getting a relatively sizeable portion of PR's
FWIW, I've just pushed a Typescript declaration file for pino to the Typescript community repository at:
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/pino/pino.d.ts
I did my best to make sure it describes the public interface accurately.
If you find anything you would like me to change, let me know.
Given that the public interface is based on the standard established by Log4j, e.g. info
, warn
, etc., shouldn't the internal level numbers match the ones used by Log4j? They have:
level name | level number |
---|---|
off | 0 |
fatal | 100 |
error | 200 |
warn | 300 |
info | 400 |
debug | 500 |
trace | 600 |
all | Number.MAX_VALUE |
src: http://logging.apache.org/log4j/2.x/manual/customloglevels.html
Whereas we have:
level name | level number |
---|---|
off | 100 ("silent") |
fatal | 60 |
error | 50 |
warn | 40 |
info | 30 |
debug | 20 |
trace | 10 |
all | no equivalent |
Of course, our numbers are matching Bunyan's.
would you take a pr basically doing this:
@@ -56,7 +56,7 @@ function pino (opts, stream) {
var stringify = safe ? stringifySafe : JSON.stringify
var formatOpts = safe ? null : {lowres: true}
var name = opts.name
- var level = opts.level || 'info'
+ var level = opts.level || process.env.LOG_LEVEL || 'info'
var serializers = opts.serializers || {}
var end = ',"v":' + LOG_VERSION + '}\n'
var cache = !opts.extreme ? null : {
so i don't have to pass its value into the logger? =)
is it possible to divide logging between stdout and stderr ( stderr for errors ) ?
Hi, I was reading about the extreme mode and I think it is a really good idea. I also think adding a flush timeout would help to prevent some of the potential data loss:
Kafka does that on the producer and seems to be the most optimal way of handling a high throughput data ingestion stream. Any thoughts?
Also flushing the cache on extreme mode when a termination signal is sent to the process would prevent from data being lost (I don't think it is happening right now).
...based on level, as bunyan and #106 do.
> logger.child({a: 'prop', another: 'prop'}).info('hello')
{"pid":91954,"hostname":"MacBook-Pro-3.home","level":30,"msg":"hello","time":1459513410318,"v":1,"a":"prop""another":"prop"}
Notice the lack of comma between "a":"prop" and "another":"prop"
I'm just working on a branch (will push soon) which addresses this and #19 and yields speed improvements for child loggers.
See https://github.com/pimterry/loglevel
I didn't know about this one!
todo
It would be nice to be able to provide the mapLine function as an option for the pretty stream, so that I can define my own application specific format for log lines.
I was wondering if something like Bunyan's RingBuffer would be a useful addition to pino.
It'd be useful to just buffer n-lines of logs in memory and being able to flush them manually, much like extreme mode but with manual control over the flush.
Perhaps we can expose an API on top of extreme mode?
https://github.com/trentm/node-bunyan#raw--ringbuffer-stream
Is it possible to modify the format or pattern of the logs? For example, instead of having the date first, I would like it to print the log level first.
In bunyan, loggers created from logger.child()
also have a .child()
method. It'd be nice to support this so that pino is mostly a drop-in replacement for bunyan.
Hello Matteo,
While playing with pino, I noticed a subtle bug, when stderr is redirected from bash like this:
node index.js 2> error.log
And index.js looks like
var pino = require('pino')
var log = pino(process.stderr)
log.warn('will output to stdout')
It seems related to the property _writableState
which is undefined
in this case.
So the condition opts && opts._writableState
to assign opts to the stream, can't pass.
Note that it just happens when options are omitted!
Cheers,
Benoit
I usually use nodemon
when developing nodejs servers. The issue is that it prints stuff to stdout that are not actual logs:
satazor@Andres-MacBook-Pro ~/Work/npms/npms-api
$ npm run start-dev | pino
> [email protected] start-dev /Users/satazor/Work/npms/npms-api> nodemon --watch server.js --watch index.js --watch lib --watch config --ext js,json5 server.js --log-level debug[nodemon] 1.9.2[nodemon] to restart at any time, enter `rs`[nodemon] watching: server.js index.js /Users/satazor/Work/npms/npms-api/lib/**/* /Users/satazor/Work/npms/npms-api/config/**/*[nodemon] starting `node server.js --log-level debug`[2016-07-06T13:16:44.727Z] INFO (npms-api/34423 on Andres-MacBook-Pro.local): Now listening on 127.0.0.1:3000..
module: "server"
Without piping to pino:
satazor@Andres-MacBook-Pro ~/Work/npms/npms-api
$ npm run start-dev
> [email protected] start-dev /Users/satazor/Work/npms/npms-api
> nodemon --watch server.js --watch index.js --watch lib --watch config --ext js,json5 server.js --log-level debug
[nodemon] 1.9.2
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: server.js index.js /Users/satazor/Work/npms/npms-api/lib/**/* /Users/satazor/Work/npms/npms-api/config/**/*
[nodemon] starting `node server.js --log-level debug`
{"pid":34437,"hostname":"Andres-MacBook-Pro.local","name":"npms-api","level":30,"msg":"Now listening on 127.0.0.1:3000..","time":1467811147466,"module":"server",
As you see from above, the new lines from nodemon are removed which results in weird output. As far as I remember, bunyan
didn't do this.
Are we able to get around this?
Thanks
We need instructions (and probably a nice module) to easily upload logs to cloudwatch. I know there is the cloudwatch daemon, so we might just list that. But having a little node-something can be nice.
Maybe we can just do tail-to-cloudwatch, and be done with it.
See
https://github.com/mirkokiefer/bunyan-cloudwatch
https://www.npmjs.com/package/winston-cloudwatch
I'd like to recreate the debug
value proposition in a pino compatible way
debug is a different use case (dev more than prod) - but I've also seen teams using debug for prod logging - I'm thinking, let's create a module that namespaces debug logs as per the debug
module, and applies filtering to pino.debug
logs
var logger = require('pino')()
var debug = require('pino-debug')
debug('myApp', logger)
pino.debug('ok')
$ DEBUG=myApp node my-app.js # pretty prints ok, same output as debug module
this could be as simple as overriding pino.debug
with the debug module, whenever the DEBUG var is set
When pino is in "extreme" mode it has to register handlers for process.on('exit')
(https://github.com/mcollina/pino/blob/master/pino.js#L390). These handlers are necessary so that pino can flush the extreme mode cache prior to the process exiting, or else there is the potential for data loss. After flushing the cache, pino then checks to see if its events are in the event queue (https://github.com/mcollina/pino/blob/master/pino.js#L98). If so, pino issues a process.exit()
.
It is my opinion that a logger should not be invoking process.exit
. That should be left up to the application that included pino. However, once event handlers are registered on process
the process doesn't respond to signals like SIGTERM
normally; at this point it is up to the application to deal with those signals.
I think there are a couple possible solutions:
process.exit
pino can issue its own "exit" event so that the actual application can do what it needs to do for shutdownIn either case, this moves the responsibility of terminating the process to the actual application. And it removes the surprise process.exit
within pino.
Thoughts, @mcollina @davidmarkclements ?
Hi, guys. I noticed you also write logger. I also spend some time one this 1 and 2. Of course both much faster bunyan, intel and others. I did not compared to this project actually.
Right idea i got to improve speed - message compilation. So just compile string message to function producing simple string or json string - and you will gain huge speed improvement.
var pino = require('pino')
var pretty = pino.pretty()
pretty.pipe(process.stdout)
var log = pino({
name: 'app',
safe: true
}, pretty)
log.info('This has a double quote: " ')
log.info('This does not')
{"pid":61920,"hostname":"mpb.local","name":"app","level":30,"msg":"This has a double quote: " ","time":1468521356677,"v":1}
[2016-07-14T18:35:56.682Z] INFO (app/61920 on mpb.local): This does not
Versions:
start: node app.js | pino
line: console.log(JSON.stringify({'hello': 'world'}))
leads to:
myproj/node_modules/pino/pretty.js:115
return new Date(time).toISOString()
^
RangeError: Invalid time value
at asISODate (myproj/node_modules/pino/pretty.js:115:27)
at DestroyableTransform.mapLine [as mapper] (myproj/node_modules/pino/pretty.js:94:17)
at DestroyableTransform.transform [as _transform] (myproj/node_modules/split2/index.js:33:21)
at DestroyableTransform.Transform._read (myproj/node_modules/through2/node_modules/readable-stream/lib/_stream_transform.js:159:10)
at DestroyableTransform.Transform._write (myproj/node_modules/through2/node_modules/readable-stream/lib/_stream_transform.js:147:83)
at doWrite (myproj/node_modules/through2/node_modules/readable-stream/lib/_stream_writable.js:313:64)
at writeOrBuffer (myproj/node_modules/through2/node_modules/readable-stream/lib/_stream_writable.js:302:5)
at DestroyableTransform.Writable.write (myproj/node_modules/through2/node_modules/readable-stream/lib/_stream_writable.js:241:11)
at Socket.ondata (_stream_readable.js:556:20)
at emitOne (events.js:96:13)
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.