├── .devrun ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── index.js └── package.json /.devrun: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | `boot2docker shellinit` 4 | DOCKER_IP=`boot2docker ip` 5 | 6 | docker rm -f docker-librato 2>/dev/null 7 | docker build -t _dev/docker-librato . 8 | 9 | docker run -d --name docker-librato \ 10 | -e STATSD_HOST="127.0.0.1" \ 11 | -v /var/run/docker.sock:/var/run/docker.sock \ 12 | _dev/docker-librato 13 | 14 | docker logs -f docker-librato 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Commenting this out is preferred by some people, see 24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 25 | node_modules 26 | 27 | # Users Environment Variables 28 | .lock-wscript 29 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:0.12 2 | MAINTAINER Meteorhacks 3 | 4 | COPY ./package.json /app/package.json 5 | RUN cd /app && npm install 6 | COPY . /app 7 | 8 | CMD ["node", "/app/index.js"] 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Matteo Collina 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # docker-stats-statsd 2 | 3 | Forward all your stats to Etsy's [Statsd](https://github.com/etsy/statsd), like a breeze. 4 | 5 | ## Usage as a Container 6 | 7 | The simplest way to forward all your container's log to Statsd. Given the versatility of statsd, you can configure the metrics to go to any supported backends; including Librato, Graphite. All you have to do is run this repository as a container, with: 8 | 9 | ```sh 10 | docker run \ 11 | -v /var/run/docker.sock:/var/run/docker.sock \ 12 | -e STATSD_HOST="" \ 13 | -e STATSD_PORT="" \ 14 | -e STATSD_PREFIX="" \ 15 | edyn/docker-stats-statsd 16 | ``` 17 | Note that all three options default to reasonable values (STATSD_HOST, STATSD_PORT, STATSD_PREFIX) => (127.0.0.1, 8125, "docker.") 18 | ``` 19 | 20 | ### Running container in a restricted environment. 21 | Some environments(such as Google Compute Engine) does not allow to access the docker socket without special privileges. You will get EACCES(`Error: read EACCES`) error if you try to run the container. To run the container in such environments add --privileged to the `docker run` command. 22 | 23 | Example: 24 | ```sh 25 | docker run --privileged \ 26 | -v /var/run/docker.sock:/var/run/docker.sock \ 27 | -e STATSD_HOST="" \ 28 | -e STATSD_PORT="" \ 29 | -e STATSD_PREFIX="" \ 30 | edyn/docker-stats-statsd 31 | ``` 32 | 33 | ## Building a docker repo from this repository 34 | 35 | First clone this repository, then: 36 | 37 | ```bash 38 | docker build -t docker-stats . 39 | docker run \ 40 | -v /var/run/docker.sock:/var/run/docker.sock \ 41 | docker-stats 42 | ``` 43 | 44 | ## How it works 45 | 46 | This module wraps four [Docker 47 | APIs](https://docs.docker.com/reference/api/docker_remote_api_v1.17/): 48 | 49 | * `POST /containers/{id}/attach`, to fetch the logs 50 | * `GET /containers/{id}/stats`, to fetch the stats of the container 51 | * `GET /containers/json`, to detect the containers that are running when 52 | this module starts 53 | * `GET /events`, to detect new containers that will start after the 54 | module has started 55 | 56 | This module wraps 57 | [docker-loghose](https://github.com/mcollina/docker-loghose) and 58 | [docker-stats](https://github.com/pelger/docker-stats) to fetch the logs 59 | and the stats as a never ending stream of data. 60 | 61 | All the originating requests are wrapped in a 62 | [never-ending-stream](https://github.com/mcollina/never-ending-stream). 63 | 64 | ## Credits 65 | 66 | This app is based on [Meteorhacks](https://github.com/meteorhacks/docker-librato). 67 | 68 | ## License 69 | 70 | MIT 71 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var env = require('envalid'); 2 | var StatsD = require('node-statsd'); 3 | var allcontainers = require('docker-allcontainers'); 4 | var dockerstats = require('docker-stats'); 5 | var _ = require('lodash'); 6 | var through = require('through2'); 7 | 8 | env.validate(process.env, { 9 | STATSD_HOST: {recommended: true}, 10 | STATSD_PORT: {recommended: true}, 11 | STATSD_PREFIX: {recommended: true}, 12 | }); 13 | 14 | var statsdClient = new StatsD({ 15 | host: env.get('STATSD_HOST', '127.0.0.1'), 16 | port: env.get('STATSD_PORT', 8125), 17 | prefix: env.get('STATSD_PREFIX', 'docker.'), 18 | }); 19 | 20 | /*statsdClient = { 21 | gauge: function(key, value){ 22 | console.log(key, value); 23 | } 24 | }*/ 25 | 26 | var stats = dockerstats({ 27 | docker: null, 28 | events: allcontainers({ 29 | preheat: true, 30 | docker:null}) 31 | }); 32 | 33 | stats.pipe(through.obj(update)); 34 | 35 | function update(chunk, enc, callback) { 36 | var name = chunk.name; 37 | var info = { 38 | cpu: { 39 | cpu_percent: chunk.stats.cpu_stats.cpu_usage.cpu_percent, 40 | }, 41 | memory: { 42 | usage: chunk.stats.memory_stats.usage, 43 | max_usage: chunk.stats.memory_stats.max_usage, 44 | total_rss: chunk.stats.memory_stats.stats.total_rss, 45 | total_swap: chunk.stats.memory_stats.stats.total_swap, 46 | total_pgpgin: chunk.stats.memory_stats.stats.total_pgpgin, 47 | total_pgpgout: chunk.stats.memory_stats.stats.total_pgpgout, 48 | total_pgfault: chunk.stats.memory_stats.stats.total_pgfault 49 | } 50 | }; 51 | 52 | //console.log(chunk.stats); 53 | 54 | updateContainer(name, info) 55 | callback(); 56 | } 57 | 58 | function updateContainer (name, info) { 59 | _.each(info, function(section, key){ 60 | if (!_.isObject(section)) { 61 | statsdClient.gauge(name + '.' + key, section); 62 | } else { 63 | _.each(section, function(value, metric){ 64 | statsdClient.gauge(name + '.' + key + '.' + metric, value); 65 | }); 66 | } 67 | }); 68 | } 69 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docker-stats-statsd", 3 | "version": "1.0.0", 4 | "description": "Forward all stats from all running docker containers to a statsd server", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/edyn/docker-stats-statsd.git" 8 | }, 9 | "main": "index.js", 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "Mamadou Bobo Diallo", 14 | "license": "MIT", 15 | "dependencies": { 16 | "docker-allcontainers": "^0.2.0", 17 | "docker-stats": "^0.2.0", 18 | "lodash": "^3.9.3", 19 | "envalid": "^0.1.0", 20 | "node-statsd": "^0.1.1 ", 21 | "through2": "^0.6.3" 22 | } 23 | } 24 | --------------------------------------------------------------------------------