GithubHelp home page GithubHelp logo

kkamkou / node-gelf-pro Goto Github PK

View Code? Open in Web Editor NEW
69.0 4.0 29.0 281 KB

Graylog2 client library for Node.js

Home Page: https://docs.graylog.org/docs/gelf

License: MIT License

JavaScript 99.41% Dockerfile 0.59%
gelf node-js graylog udp tcp tls ssl

node-gelf-pro's Introduction

gelf pro

node-gelf - Graylog2 client library for Node.js. GELF - The Graylog Extended Log Format.

Build Status Coverage Status

Installation

"dependencies": {
  "gelf-pro": "~1.3" // see the "releases" section
}

npm install gelf-pro (ALL node.js versions are supported [0.x to 20.x] :)

Library depends on: lodash#~4.17

Initialization

var log = require('gelf-pro');

Adapters

Warning

To ensure consistent behavior, none of the existing adapters re-use the socket connection. Re-using socket connections can lead to resource leakage, complexity in state management, concurrency issues, security risks, and may not always provide significant performance benefits. It's often simpler and safer to establish new connections as needed rather than re-using existing ones, ensuring better resource utilization and reducing potential complications in network communication.

There are multiple (1, 2) variants available for you to borrow from and create a new adapter. See related section.

  • UDP (with deflation and chunking)
    • Input: GELF UDP
  • TCP
    • Input: GELF TCP (with Null frame delimiter)
  • TCP via TLS(SSL)
    • Input: GELF TCP (with Null frame delimiter and Enable TLS)

Note

Within a more or less stable network (which is most likely), I would recommend using the udp adapter. I would also recommend it for an average to high-loaded project. For sensitive information, the tcp-tls adapter is recommended.

Configuration

// simple
log.setConfig({adapterOptions: {host: 'my.glog-server.net'}});

// advanced
log.setConfig({
  fields: {facility: "example", owner: "Tom (a cat)"}, // optional; default fields for all messages
  filter: [], // optional; filters to discard a message
  transform: [], // optional; transformers for a message
  broadcast: [], // optional; listeners of a message
  levels: {}, // optional; default: see the levels section below
  aliases: {}, // optional; default: see the aliases section below
  adapterName: 'udp', // optional; currently supported "udp", "tcp" and "tcp-tls"; default: udp
  adapterOptions: { // this object is passed to the adapter.connect() method
    // common
    host: '127.0.0.1', // optional; default: 127.0.0.1
    port: 12201, // optional; default: 12201
    // ... and so on
    
    // tcp adapter example
    family: 4, // tcp only; optional; version of IP stack; default: 4
    timeout: 1000, // tcp only; optional; default: 10000 (10 sec)
    
    // udp adapter example
    protocol: 'udp4', // udp only; optional; udp adapter: udp4, udp6; default: udp4
    
    // tcp-tls adapter example
    key: fs.readFileSync('client-key.pem'), // tcp-tls only; optional; only if using the client certificate authentication
    cert: fs.readFileSync('client-cert.pem'), // tcp-tls only; optional; only if using the client certificate authentication
    ca: [fs.readFileSync('server-cert.pem')] // tcp-tls only; optional; only for the self-signed certificate
  }
});

log.setConfig merges the data. Therefore, you can call it multiple times.

Basic functionality

var extra = {tom: 'cat', jerry: 'mouse', others: {spike: 1, tyke: 1}};

log.info("Hello world", extra, function (err, bytesSent) {});
log.info("Hello world", function (err, bytesSent) {});
log.info("Hello world", extra);
log.info("Hello world");

log.error('Oooops.', new Error('An error message'));
// ^-- extra becomes: {short_message: 'Oooops.', _error_message: 'An error message', _error_stack: Error's stack}

log.error(new Error('An error message'));
// ^-- extra becomes: {short_message: 'An error message', full_message: Error's stack}

log.message(new Error('An error message'), 3); // same as previous
Extra

In case extra is a plain object, the library converts it to a readable format. Other values are converted to string. The acceptable format of a key is: ^[\w-]$

log.info(
  'a new msg goes here',
  {me: {fname: 'k', lname: 'k', bdate: new Date(2000, 01, 01)}}
);
// ^-- extra becomes: {_me_fname: 'k', _me_lname: 'k', _me_bdate: 'Tue Feb 01 2000 00:00:00 GMT+0100 (CET)'}
Filtering

Sometimes we have to discard a message which is not suitable for the current environment. It is NOT possible to modify the data.

log.setConfig({
  filter: [
    function (message) { // rejects a "debug" message
      return (message.level < 7);
    }
  ]
});
Transforming

transforming happens after filtering. It is possible to modify the data.

log.setConfig({
  transform: [
    function (message) { // unwind an error
      if (_.isError(message.error)) {
        message.error = {message: message.error.message, stack: message.error.stack};
      }
      return message;
    }
  ]
});
Broadcasting

broadcasting happens after transforming. It is NOT possible to modify the data.

log.setConfig({
  broadcast: [
    function (message) { // broadcasting to console
      console[message.level > 3 ? 'log' : 'error'](message.short_message, message);
    }
  ]
});

Levels (1, 2, 3)

Default:
{emergency: 0, alert: 1, critical: 2, error: 3, warning: 4, notice: 5, info: 6, debug: 7}
Example: log.emergency(...), log.critical(...), etc.
Custom example: {alert: 0, notice: 1, ...}

Third party adapters

You can force using custom adapter by setting the adapter right after initialisation. The signature might be found here.

  var log = require('gelf-pro');
  var myFancyAdapter = require('...');
  log.adapter = myFancyAdapter;
  // (!) adapterName and adapterOptions will be ignored

Aliases

Default: {log: 'debug', warn: 'warning'}
Example: log.log(...) -> log.debug(...), log.warn(...) -> log.warning(...), etc.
Custom example: {red: 'alert', yellow: 'notice', ...}

Tests

Cli

npm install
npm test

Docker

[sudo] docker build --no-cache -t node-gelf-pro .
[sudo] docker run -ti --rm -v "${PWD}:/opt/app" -w "/opt/app" node-gelf-pro

Contributors

License

MIT

node-gelf-pro's People

Contributors

alxmiron avatar dependabot[bot] avatar gdoron avatar joelharkes avatar jucrouzet avatar kkamkou avatar korllan avatar kurrestahlberg avatar mkalam-alami avatar snoretrain avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

node-gelf-pro's Issues

Validation for a custom short_message field

Just wanted to my share my experience and suggest an improvement. It would be nice if the "message" parameter had type validation to make sure an object isn't passed in but only a string or error object. Because it's possible to pass in an error - I misunderstood the API documentation and thought it was possible to pass in an object. Since there's no type validation I ended up with this error (in case anyone googles this "bug") in Graylog but got no error from the node-gelf-pro library:

java.lang.IllegalArgumentException: GELF message <message_id> (received from <ip_address>) has invalid "short_message"

Type validation is also nice in case somone accidentally passes in an object (or different type) when they meant to pass in a string. How the codebase currently works that would cause a bug which would be very hard to detect since it would be "silent".

Angular support

Is it possible to use node-gelf-pro with Angular? I am getting the following errors when I compile the project after following the installation guide.

ERROR in ./node_modules/gelf-pro/lib/adapter/udp.js
Module not found: Error: Can't resolve 'dgram' in '.../node_modules/gelf-pro/lib/adapter'
ERROR in ./node_modules/gelf-pro/lib/adapter/tcp.js
Module not found: Error: Can't resolve 'net' in '.../node_modules/gelf-pro/lib/adapter'
ERROR in ./node_modules/gelf-pro/lib/adapter/tcp-tls.js
Module not found: Error: Can't resolve 'tls' in '.../node_modules/gelf-pro/lib/adapter'

I tried manually installing e.g. dgram but the error still persists.

UDP Adapter: Ability to pass dgram options

Does the UDP Adapter support passing in options that the underlying drgam.createSocket supports? The reason we ask is that we would like to pass a custom dns lookup function in order to support DNS Caching. If not, is it possible to add the feature?

My graylog2 server not receiving any log whn using node-gelf-pro

  var grayLog = require("gelf-pro");
  grayLog.setConfig({
    adapterName: "tcp",
    timeout: 1000,
    host: "192.168.0.102",
    port: 12203,
    family: 4
  });

// ... later

 const data = { label: "label", message: "DONE", duration: 123 };
  grayLog.info(JSON.stringify(data) + "\x00");

I know my server and configuration is working because I call bellow from shell and it works since I can see log added to the input.

echo -e '{"label":"get_user","message":"DONE","duration":123.2}\x00' | netcat -w 1 localhost 12203

TIA

bytes can be at most 32766 in length

IllegalArgumentException[Document contains at least one immense term in field="error_stack" (whose UTF8 encoding is longer than the max length 32766), all of which were skipped. Please correct the analyzer to not produce such terms. The prefix of the first immense term is: '[82, 97, 110, 103, 101, 69, 114, 114, 111, 114, 58, 32, 77, 97, 120, 105, 109, 117, 109, 32, 99, 97, 108, 108, 32, 115, 116, 97, 99, 107]...', original message: bytes can be at most 32766 in length; got 1028169]; nested: MaxBytesLengthExceededException[bytes can be at most 32766 in length; got 1028169];

Message Length clarification

Hi @kkamkou ,

With regards to my previous question in #24, is 32766 bytes the graylog recommended maxlength for a field in a message? Can you direct me to the documentation link if it is so?

TCP Timeout creates Exceptions

If the timeout has a low value and many logs are generated the node application shuts down with the following exception:

 .../gelfTest/node_modules/async/dist/async.js:844
            if (fn === null) throw new Error("Callback was already called.");
                             ^

Error: Callback was already called.
    at .../gelfTest/node_modules/async/dist/async.js:844:36
    at Socket.<anonymous> (.../gelfTest/node_modules/gelf-pro/lib/adapter/tcp.js:37:11)
    at emitOne (events.js:96:13)
    at Socket.emit (events.js:188:7)
    at Socket.<anonymous> (.../gelfTest/node_modules/gelf-pro/lib/adapter/tcp.js:33:18)
    at Socket.g (events.js:291:16)
    at emitNone (events.js:86:13)
    at Socket.emit (events.js:185:7)
    at Socket._onTimeout (net.js:334:8)
    at tryOnTimeout (timers.js:232:11)

This can be recreated with the following code, if the greylog server is running.

var log = require('gelf-pro');

log.setConfig({
  adapterName: 'tcp', // optional; currently supported "udp" and "tcp"; default: udp
  adapterOptions: {
    family: 4, // tcp only; optional; version of IP stack; default: 4
    timeout: 100, // tcp only; optional; default: 10000 (10 sec)
    host: '127.0.0.1', // optional; default: 127.0.0.1
    port: 12201, // optional; default: 12201
  },
});

for (var i = 0; i< 1000; i++) {
  log.error("Test");
}

Why is id field dropped from message?

I have message with id field and that was not being transmitted. Looking at code it indeed is deleted from message with comment that it is not possible to send id. Seemed kind of arbitrary restriction so I checked the GELF spec and it has no special meaning to field named id.

Tested modifying code to not drop the id and it worked perfectly so is there any real reason to drop the id field?

I'm using TCP output to send messages to Graylog 2.

Notify in case of a bogus usage

It is possible to call it like this:
glog.info('Example message', 'Exception')

Which is transformed to an array of chars. We should notify in this case.

Drop support of dead node.js releases (end-of-life versions)

Drop these versions:

End-of-Life Releases

Release Status Codename Initial Release Active LTS Start Maintenance LTS Start End-of-life
v0.10.x End-of-Life - 2013-03-11 - 2015-10-01 2016-10-31
v0.12.x End-of-Life - 2015-02-06 - 2016-04-01 2016-12-31
4.x End-of-Life [Argon][] 2015-09-08 2015-10-01 2017-04-01 2018-04-30
5.x End-of-Life 2015-10-29 2016-06-30
7.x End-of-Life 2016-10-25 2017-06-30
9.x End-of-Life 2017-10-01 2018-06-30

Code Climate badge

Some issues are pretty questionable, nevertheless people need the badge to be green

TCP adapter it doesn't work properly

Hi,
I'm trying to use the module with the TCP adapter but seems it doesn't work properly. Every message sent to the graylog server it's has the level set as -1, the short_message as the whole extra field.

I use the .message function passing message, level extra and a callback function. I tried to use the al other level function like info warn but nothing changes. I also tried to use a transform function and set those parameters as the extra parameter (extra is a JSON in my case) but nothing change.

Let me know if you need some other info from me.

Clean null byte from the tcp message

Example (refs #32):

const data = { label: "label", message: "DONE", duration: 123 };
grayLog.info(JSON.stringify(data) + "\x00");

We need to remove the null byte from tcp and tcp-tls adapters. Udp works as expected.

TCP TLS Support

Does this module support TLS encryption of TCP connection to graylog?

UTF8 encoding is longer than the max length 32766

IllegalArgumentException[Document contains at least one immense term in field="error_stack" (whose UTF8 encoding is longer than the max length 32766), all of which were skipped. Please correct the analyzer to not produce such terms. The prefix of the first immense term is: '[83, 121, 110, 116, 97, 120, 69, 114, 114, 111, 114, 58, 32, 47, 104, 111, 109, 101, 47, 107, 105, 114, 105, 108, 108, 47, 119, 111, 114, 107]...', original message: bytes can be at most 32766 in length; got 84418]; nested: MaxBytesLengthExceededException[bytes can be at most 32766 in length; got 84418];

Typescript: Property 'info' does not exist on type 'typeof import("gelf-pro") ...

Hello!

I am getting the error Property 'info' does not exist on type 'typeof import("gelf-pro")'. when importing this package:

import * as log from 'gelf-pro';

log.info('Hello world', { test: 123 }, function (err, bytesSent) { // Property 'info' does not exist....
    console.log('err, bytes', err, bytesSent);
});

However it works fine when I use it with require:
const log = require('gelf-pro');

How can I use it with import? It's a NestJS TS Application.

ERR_SOCKET_DGRAM_NOT_RUNNING error when chunking request body(fix suggested)

Hi! I'm using gelf-pro as a tool to send my app's logs through UDP. Recently I started to get ERR_SOCKET_DGRAM_NOT_RUNNING exception from time to time.
Here's an error trace:

Error [ERR_SOCKET_DGRAM_NOT_RUNNING]: Not running
at new NodeError (node:internal/errors:363:5)
    at healthCheck (node:dgram:908:11)
    at Socket.close (node:dgram:740:3)
    at cbResults (path/to/my/app/node_modules/gelf-pro/lib/adapter/udp.js:75:14)
    at /path/to/my/app/node_modules/gelf-pro/lib/adapter/udp.js:118:13
    at processTicksAndRejections (node:internal/process/task_queues:83:21)

As specified in the stack trace - the error happens when Socket.close is called.
After investigation I found that this happens only when request body is more than 1388 bytes and gelf-pro divides body in chunks.
The bug is in this code(from /lib/adapter/udp.js:103):

for (var idx in chunks) {
      if (isInterrupted) {
        break;
      }
      var chunk = chunks[idx],
        packet = buffer
          .from(self.specification.magicBytes.concat(packetId, idx, chunksCount, chunk));
      client.send(
        packet, 0, packet.length, self.options.port, self.options.host,
        function (err, bytesSent) {
          if (err) { return cbResults(err); }
          bytesSentTotal += bytesSent;
          /* istanbul ignore else */
          if (idx >= chunksCount - 1) {
            cbResults(err, bytesSentTotal);
          }
        }
      );
    }

More specifically in this closure:

if (idx >= chunksCount - 1) {
            cbResults(err, bytesSentTotal);
          }

Here idx is specified to check whether we arrived at the end of chunks array or not, but because of how JavaScript variable scope works what actually happens is - idx is always equal to chunksCount - 1 and cbResults is called on every loop, not only on the last one (hence ERR_SOCKET_DGRAM_NOT_RUNNING error because we try to close udp connection multiple times). Great example of how and why it works like this is provided here.

So here's a fix I came up with. What's important to note - in order for this fix to work you must use const(or let), not var(because var variable are not scope bound and by using var we actually do the same thing).

diff --git a/node_modules/gelf-pro/lib/adapter/udp.js b/node_modules/gelf-pro/lib/adapter/udp.js
index 58e452d..431b38c 100644
--- a/node_modules/gelf-pro/lib/adapter/udp.js
+++ b/node_modules/gelf-pro/lib/adapter/udp.js
@@ -101,20 +101,21 @@ adapter.send = function (message, callback) {
 
     var packetId = Array.prototype.slice.call(crypto.randomBytes(8));
     for (var idx in chunks) {
+      const capturedIndex = idx;
       if (isInterrupted) {
         break;
       }
       var chunk = chunks[idx],
         packet = buffer
           .from(self.specification.magicBytes.concat(packetId, idx, chunksCount, chunk));
       client.send(
         packet, 0, packet.length, self.options.port, self.options.host,
         function (err, bytesSent) {
           if (err) { return cbResults(err); }
           bytesSentTotal += bytesSent;
           /* istanbul ignore else */
-          if (idx >= chunksCount - 1) {
+          if (capturedIndex >= chunksCount - 1) {
             cbResults(err, bytesSentTotal);
           }
         }

This issue body was partially generated by patch-package.

tcp.js:42: add deflation with GELF 2.0

The puzzle 37-7e52116e from #37 has to be resolved:

// @todo #37:60m add deflation with GELF 2.0

The puzzle was created by Kanstantsin Kamkou on 03-Apr-18.

Estimate: 60 minutes, role: DEV.

If you have any technical questions, don't ask me, submit new tickets instead. The task will be "done" when the problem is fixed and the text of the puzzle is removed from the source code. Here is more about PDD and about me.

socket reuse

We have a very busy system and use a TCP connection to graylog. We're starting to see errors relating to open file handles and it seems that we have several thousand sockets open to our graylog server. I was wondering why this TCP adapter doesn't reuse the socket? Why would you need more than one?

Add filtering functionality

It'll be nice to have a native support of the level filtering for the library itself.

filter: function (message, extra) {
  return true;
});

Crash on setConfig method

Hello,

I'm experiencing an issue with your library when I'm using the method setConfig() :

node_modules\gelf-pro\lib\gelf-pro.js:57
  this.config = _.merge({}, this.config, conf);
              ^
TypeError: Cannot set property config of #<Object> which has only a getter

Do you have any fix ?

Sincerly

UDP adapter max chunks count

Hi,

I've come to an issue about the maximum number of chunks using UDP adapter.

The code limits it to 20 but the documentation suggests a maximum of 128.

Is there any reason for that limit not following the specs ?

Delays releasing UDP port on DNS timeout.

I discovered this because of a very chatty service using this library running my server out of available ports to send messages to Graylog.

I'm not sure of a good way to reproduce this issue or test for it, but the errors that I run into are:

null: 'uncaughtException called: Error [ERR_SOCKET_CANNOT_SEND]: Unable to send data'
{{my error callback}}
{ Error: getaddrinfo EAI_AGAIN {{my graylog host}}
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:57:26)
  errno: 'EAI_AGAIN',
  code: 'EAI_AGAIN',
  syscall: 'getaddrinfo',
  hostname: '{{my graylog host}}' }

I believe that it may be the result of the callback to async.waterfall calling send's callback not as a result of client.close().

PR incoming.

Authentication

Apologies for posting doubts here instead of any bug/feature recommendations. Doing mainly because the support is quick.

I was wondering if the library supports any authentication mechanism to allow only authorised logging requests?

Can I use multiple GELF configurations?

Is it possible to have multiple logger instances? Each one would connect to a different Graylog server and have its own configuration.

From my reading of the source code it looks like the logger object is a singleton.

Error: Bad socket type specified. Valid types are: udp4, udp6

This package looks like a fit for something I'm trying to do. But I can't get past the error below. I'm trying to follow the example configuration from the README.

Error: Bad socket type specified. Valid types are: udp4, udp6
    at newHandle (dgram.js:59:9)
    at new Socket (dgram.js:89:16)
    at Object.exports.createSocket (dgram.js:109:10)
    at udp._createSocket (/Users/dave/devel/integration-tools/node_modules/gelf-pro/lib/adapter/udp.js:42:16)
    at udp.send (/Users/dave/devel/integration-tools/node_modules/gelf-pro/lib/adapter/udp.js:66:21)
    at gelf.send (/Users/dave/devel/integration-tools/node_modules/gelf-pro/lib/gelf-pro.js:110:21)
    at /Users/dave/devel/integration-tools/node_modules/gelf-pro/lib/gelf-pro.js:152:14
    at doNTCallback0 (node.js:419:9)
    at process._tickCallback (node.js:348:13)

Manually setting levels or aliases doesn't expose corresponding methods

Let's say you add an additional level like this:

const log = require('gelf-pro');

log.setConfig({
  emergency: 0,
  alert: 1,
  critical: 2,
  error: 3,
  warning: 4,
  notice: 5,
  info: 6,
  debug: 7,
  trace: 8,
});

log.trace() will be undefined. This is because these methods are defined while requiring the module, with no chances to update the levels or aliases before.

Maybe the methods should be redefined while calling setConfig().

plain object -> readable format

Hi,
Is there a way to turn off this capability to convert a plain object into readable format?
I mean this one:
log.info( 'a new msg goes here', {me: {fname: 'k', lname: 'k', bdate: new Date(2000, 01, 01)}} ); // ^-- extra becomes: {_me_fname: 'k', _me_lname: 'k', _me_bdate: 'Tue Feb 01 2000 00:00:00 GMT+0100 (CET)'}

Manually pass the log level

I am writing a good plugin using gelf pro.

I was wondering if you would be open to an option to manually pass the log level. (I am happy to submit a PR)

As hapi logs don't map directly to syslog error levels I want to give the user an option to configure based on the log 'event' and 'tags' doc what level should be used.

UDP: Error handling of long messages causes Exception in async module

Hi,

When the udp adapter logs a message which is bigger than one chunk and an error occurs it still tries to send the other chunks. If another chunk fails you will get the following error:

Error: Callback was already called.
    at <...>\node_modules\async\dist\async.js:844:36
    at doSend (dgram.js:368:7)
    at afterDns (dgram.js:358:5)
    at GetAddrInfoReqWrap.asyncCallback [as callback] (dns.js:62:16)

This error caused some of your applications to crash.

You can easily reproduce this behavior when you try to send a log message to a non existing / resolvable address (which was the case in our system). See the following test code:

const gelf = require('gelf-pro');

gelf.setConfig({
  adapterOptions: {
    host: 'aUnresolvableAddressMaybeBecauseOfATypo.com',
  },
});

// some randomly generated 3000 byte string to get more than one chunk
const randomLongContent = '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';

gelf.debug(randomLongContent, (err, bytesSent) => {
  console.log({ err, bytesSent });
});

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.