Git Product home page Git Product logo

dkll's Introduction

DKLL build Go Report Card Coverage Status Docker Automated build

Logging server, agent and CLI client for dockerized infrastructure.

  • each host runs dkll agent container collecting logs from all docker containers on the host.
  • the agent can store logs locally, or/and forward them to remote syslog server.
  • server (dkll server) container installed on another host, acts as syslog server and stores logs.
  • server also provides http api to access logs.
  • client (dkll client) is a binary command-line utility to read/filter/search and follow logs.

note: dkll agent can be used as a standalone container without server and client. In this case it will be a local collector of all logs and/or forwarder to any (external or internal) syslog server.

Build from the source

  1. clone this repo - git clone https://github.com/umputun/dkll.git
  2. build the logger - cd dkll && docker build -t umputun/dkll .

alternatively use provided Makefile, i.e. make test lint docker

Server

Server mode runs syslog server collecting records sent by dkll agent (see below). All records parsed, analyzed and stored in mongodb (capped collection). Optionally, records can be sent to <host>/<container>.log files as well as to merged dkll.log file. All files rotated and compressed automatically.

Usage

  1. copy provided compose-server.yml to docker-compose.yml
  2. adjust docker-compose.yml if needed.
  3. pull containers - docker-compose pull
  4. start server - docker-compose up -d

command line options and env params:

dkll [OPTIONS] server [server-OPTIONS]

Application Options:
      --dbg                              show debug info [$DEBUG]

Help Options:
  -h, --help                             Show this help message

[server command options]
      --api-port=                      rest server port (default: 8080) [$API_PORT]
      --syslog-port=                   syslog server port (default: 5514) [$SYSLOG_PORT]
      --mongo=                         mongo URL [$MONGO]
      --mongo-timeout=                 mongo timeout (default: 5s) [$MONGO_TIMEOUT]
      --mongo-size=                    max collection size (default: 10000000000) [$MONGO_SIZE]
      --mongo-docs=                    max docs in collection (default: 50000000) [$MONGO_DOCS]
      --backup=                        backup log files location [$BACK_LOG]
      --merged                         enable merged log file [$BACK_MRG]

    container:
      --limit.container.max-size=      max log size, in megabytes (default: 100) [$MAX_SIZE]
      --limit.container.max-backups=   max number of rotated files (default: 10) [$MAX_BACKUPS]
      --limit.container.max-age=       max age of rotated files, days (default: 30) [$MAX_AGE]

    merged:
      --limit.merged.max-size=         max log size, in megabytes (default: 100) [$MAX_SIZE]
      --limit.merged.max-backups=      max number of rotated files (default: 10) [$MAX_BACKUPS]
      --limit.merged.max-age=          max age of rotated files, days (default: 30) [$MAX_AGE]
  • mongo URL specify the standard mongodb connection string with db and collection extra parameters, e.g. mongodb://localhost:27017/admin?db=dkll&collection=logs
  • if backup defined dkll server will make host/container.log files in backup directory
  • merged parameter produces a single dkll.log file with all received records.

Parameters can be set in command directive (see docker-compose.yml) or as environment vars.

API

Records format (response):

type LogEntry struct {
	ID        string    `json:"id"`         // record ID
	Host      string    `json:"host"`       // host name
	Container string    `json:"container"`  // container
	Pid       int       `json:"pid"`        // process id
	Msg       string    `json:"msg"`        // log message
	Ts        time.Time `json:"ts"`         // reported time 
	CreatedTs time.Time `json:"cts"`        // creation time
}
  • GET /v1/last - get last records LogEntry
  • POST /v1/find - find records for given Request
type Request struct {
	LastID     string    `json:"id"`                   // get records after this id
	Limit      int       `json:"max"`                  // max size of response, i.e. number of messages one request can return
	Hosts      []string  `json:"hosts,omitempty"`      // list of hosts, can be exact match or regex in from of /regex/
	Containers []string  `json:"containers,omitempty"` // list of containers, can be regex as well
	Excludes   []string  `json:"excludes,omitempty"`   // list of excluded containers, can be regex
	FromTS     time.Time `json:"from_ts,omitempty"`    
	ToTS       time.Time `json:"to_ts,omitempty"`
}
  • POST /v1/stream?timeout=10s - find records for given Request and stream it. Terminate stream on timeout inactivity.

Storage

DKLL server uses mongo db to save and access records. It is possible and almost trivial to replace mongo with different backend by implementing 2 interfaces (Publisher and DataService) with just 3 functions:

  • Publish(records []core.LogEntry) (err error)
  • LastPublished() (entry core.LogEntry, err error)
  • Find(req core.Request) ([]core.LogEntry, error)

Security and auth

Both syslog and http don't restrict access. To allow some basic auth the simplest way is to run dkll server behind nginx-le proxy with basic auth configured on nginx level. To limit access to syslog port (514) firewall (internal or external) cab be used.

TODO: example

Agent

Agent container runs on each host and collects logs from all containers on the host. The logs sent to remote dkll server and/or stored and rotated locally. The agent can intercept logs from containers configured with a logging driver that works with docker logs (journald and json-file).

To deploy agent use provided compose-agent.yml

dkll [OPTIONS] agent [agent-OPTIONS]

Application Options:
      --dbg                show debug info [$DEBUG]

Help Options:
  -h, --help               Show this help message

[agent command options]
      -d, --docker=        docker host (default: unix:///var/run/docker.sock) [$DOCKER_HOST]
          --syslog         enable logging to syslog [$LOG_SYSLOG]
          --syslog-host=   syslog host (default: 127.0.0.1:514) [$SYSLOG_HOST]
          --syslog-prefix= syslog prefix (default: docker/) [$SYSLOG_PREFIX]
          --files          enable logging to files [$LOG_FILES]
          --max-size=      size of log triggering rotation (MB) (default: 10) [$MAX_SIZE]
          --max-files=     number of rotated files to retain (default: 5) [$MAX_FILES]
          --max-age=       maximum number of days to retain (default: 30) [$MAX_AGE]
          --mix-err        send error to std output log file [$MIX_ERR]
          --loc=           log files locations (default: logs) [$LOG_FILES_LOC]
      -x, --exclude=       excluded container names [$EXCLUDE]
      -i, --include=       included container names [$INCLUDE]
      -j, --json           wrap message with JSON envelope [$JSON]
          --demo           demo mode, generates simulated log entries [$DEMO]
          --demo-every=    demo interval (default: 3s) [$DEMO_EVERY]
      
  • at least one of destinations (files or syslog) should be allowed
  • location of log files can be mapped to host via volume, ex: - ./logs:/srv/logs (see compose-agent.yml)
  • both --exclude and --include flags are optional and mutually exclusive, i.e. if --exclude defined --include not allowed, and vise versa.

If you use the provided docker image, by default docker agent will run with UID=1001. Make sure that the access for docker socket granted for that user. Another way is specifing APP_UID environment variable for the agent container with either UID with docker privileges or 0 for running with root privileges.

Demo mode

Defining --demo or $DEMO switches agent to demo mode emitting fake log messages from fake containers. Everything preconfigured in compose-demo.yml and can be activated with MONGO_PASSWD=<any random password> docker-compose -f compose-demo.yml up.

Client

Command line client accessing dkll server and printing the content.

Usage

DKLL client should be used directly as a compiled binary. You can get precompiled release or build it from the source (make deploy).

dkll [OPTIONS] client [client-OPTIONS]


Application Options:
      --dbg       show debug info [$DEBUG]

Help Options:
  -h, --help      Show this help message

[client command options]
      -a, --api=  API endpoint (client) [$DKLL_API]
      -c=         show container(s) only
      -h=         show host(s) only
      -x=         exclude container(s)
      -m          show syslog timestamp
      -p          show pid
      -s          show syslog messages
      -f          follow mode
      -t          tail mode
      -n=         show N records
      -g=         grep on entire record
      -G=         un-grep on entire record
          --tail= number of initial records (default: 10)
          --tz=   time zone (default: Local)
  • containers (-c), hosts (-h) and exclusions (-x) can be repeated multiple times.
  • both containers and hosts support regex inside "/", i.e. /^something/

Development

  • go v1.11 and above required
  • repository uses modules and should be cloned outside of GOPATH
  • dkll server tests need mongo up and running, i.e. docker run -d --name=mongo -p 27017:27017 mongo

dkll's People

Contributors

dimetron avatar umputun avatar vblz 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

Watchers

 avatar  avatar  avatar  avatar  avatar

dkll's Issues

panic: interface conversion: interface {} is nil, not string

I hate panic!

I run service in docker swarm. Mongo 4.2 Mongo started.

docker-logger_server.1.svglcz9oc3ng@docker-desktop    | 2022/03/14 16:37:56.562 [DEBUG] {cmd/server.go:53 cmd.ServerCmd.Run} server mode activated --
docker-logger_server.1.svglcz9oc3ng@docker-desktop    | 2022/03/14 16:37:56.562 [INFO]  {cmd/server.go:122 cmd.ServerCmd.makeWriters} backup files location /srv/logs
docker-logger_server.1.svglcz9oc3ng@docker-desktop    | 2022/03/14 16:37:56.562 [DEBUG] {cmd/server.go:97 cmd.makeMongoClient} make mongo client for "mongodb://admin:pass@mongo:27017"
docker-logger_server.1.svglcz9oc3ng@docker-desktop    | panic: interface conversion: interface {} is nil, not string

Where is from panic?

umputun/dkll build error

$ docker run --rm umputun/dkll /srv/dkll server
init
execute /srv/init.sh
/init.sh: line 7: /srv/init.sh: not found
/srv/init.sh failed
$ docker images umputun/dkll
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
umputun/dkll        latest              409bb001238c        9 minutes ago       44.3MB

It's latest on 14.06.2019 08:40 UTC

TCP syslog writer should redial on connection lost (agent)

In case if dkll server failed/restarted and communication between agent and server is non-default tcp, agent writers can lose connection quietly. It has a repeater, but this one is on the dial stage only. and works on new container event.

Demo does not work without `MONGO_PASSWD` env var

As stated in https://github.com/umputun/dkll#demo-mode demo mode can be started by docker-compose -f compose-demo.yml up but if there is no MONGO_PASSWD env var, mongo does not start and other services don't work well too.

Logs
WARNING: The MONGO_PASSWD variable is not set. Defaulting to a blank string.
Creating dkll_mongo-dkll_1 ... done
Creating dkll-agent        ... done
Creating dkll-server       ... done
Attaching to dkll-agent, dkll-server, dkll_mongo-dkll_1
dkll-agent     | init
dkll-agent     | execute /srv/init.sh
dkll-agent     | timezone=America/Chicago
dkll-agent     | Fri Jun 14 03:51:18 CDT 2019
dkll-agent     | execute /srv/dkll agent
dkll-agent     | dkll agent master-6e2ca72-
dkll-agent     | 2019/06/14 03:51:18.792 [DEBUG] {agent/event_loop.go:62 agent.(*EventLoop).Run} received event {ContainerID:nginx ContainerName:nginx Group:system TS:2019-06-14 03:51:18.792513 -0500 CDT m=+0.003179201 Status:true}
dkll-agent     | 2019/06/14 03:51:18 [WARN] running agent in demo mode
dkll-agent     | 2019/06/14 03:51:18 [DEBUG] create log writer for system/nginx
dkll-agent     | 2019/06/14 03:51:18 [INFO] loggers created for logs/system/nginx.log and logs/system/nginx.err, max.size=10M, max.files=5, max.days=30
dkll-agent     | 2019/06/14 03:51:18.794 [DEBUG] {agent/docker_logger.go:39 agent.NewContainerLogStreamer} initialize ContainerLogStreamer with {ID:nginx Name:nginx LogWriter:0xc000076640 ErrWriter:0xc000076690 LogsEmitter:0xc0001463b8}
dkll-agent     | 2019/06/14 03:51:18.794 [DEBUG] {agent/event_loop.go:96 agent.(*EventLoop).onEvent} streaming for 1 containers
dkll-agent     | 2019/06/14 03:51:18.794 [DEBUG] {agent/event_loop.go:62 agent.(*EventLoop).Run} received event {ContainerID:mongo ContainerName:mongo Group:db TS:2019-06-14 03:51:18.7925174 -0500 CDT m=+0.003183601 Status:true}
dkll-agent     | 2019/06/14 03:51:18.794 [INFO]  {agent/docker_logger.go:52 agent.(*ContainerLogStreamer).Run} start log streamer for nginx
dkll-agent     | 2019/06/14 03:51:18 [DEBUG] create log writer for db/mongo
dkll-agent     | 2019/06/14 03:51:18 [INFO] loggers created for logs/db/mongo.log and logs/db/mongo.err, max.size=10M, max.files=5, max.days=30
dkll-agent     | 2019/06/14 03:51:18.797 [DEBUG] {agent/docker_logger.go:39 agent.NewContainerLogStreamer} initialize ContainerLogStreamer with {ID:mongo Name:mongo LogWriter:0xc0001163c0 ErrWriter:0xc000116410 LogsEmitter:0xc0001463b8}
dkll-agent     | 2019/06/14 03:51:18.797 [DEBUG] {agent/event_loop.go:96 agent.(*EventLoop).onEvent} streaming for 2 containers
dkll-agent     | 2019/06/14 03:51:18.797 [DEBUG] {agent/event_loop.go:62 agent.(*EventLoop).Run} received event {ContainerID:rest ContainerName:rest Group:app TS:2019-06-14 03:51:18.7925195 -0500 CDT m=+0.003185701 Status:true}
dkll-agent     | 2019/06/14 03:51:18.797 [INFO]  {agent/docker_logger.go:52 agent.(*ContainerLogStreamer).Run} start log streamer for mongo
dkll-agent     | 2019/06/14 03:51:18 [DEBUG] create log writer for app/rest
dkll-agent     | 2019/06/14 03:51:18 [INFO] loggers created for logs/app/rest.log and logs/app/rest.err, max.size=10M, max.files=5, max.days=30
dkll-agent     | 2019/06/14 03:51:18.800 [DEBUG] {agent/docker_logger.go:39 agent.NewContainerLogStreamer} initialize ContainerLogStreamer with {ID:rest Name:rest LogWriter:0xc0001166e0 ErrWriter:0xc000116730 LogsEmitter:0xc0001463b8}
dkll-agent     | 2019/06/14 03:51:18.800 [DEBUG] {agent/event_loop.go:96 agent.(*EventLoop).onEvent} streaming for 3 containers
dkll-agent     | 2019/06/14 03:51:18.800 [INFO]  {agent/docker_logger.go:52 agent.(*ContainerLogStreamer).Run} start log streamer for rest
dkll-server    | init
dkll-server    | execute /srv/init.sh
dkll-server    | timezone=America/Chicago
dkll-server    | Fri Jun 14 03:51:20 CDT 2019
dkll-server    | execute /srv/dkll server
dkll-server    | dkll server master-6e2ca72-
dkll-server    | 2019/06/14 03:51:20.026 [INFO]  {server/mongo.go:53 server.NewMongo} make new mongo server with dial={Addrs:[mongo-dkll] Timeout:5s Database:admin ReplicaSetName: Source: Service: ServiceHost: Mechanism: Username: Password: PoolLimit:0 PoolTimeout:0s ReadTimeout:0s WriteTimeout:0s AppName:dkll ReadPreference:<nil> Safe:{W:0 WMode: RMode: WTimeout:0 FSync:false J:false} FailFast:false Direct:false MinPoolSize:0 MaxIdleTimeMS:0 DialServer:<nil> Dial:<nil>}, {MaxDocs:50000000 MaxCollectionSize:10000000000 Delay:10s DBName:dkll Collection:msgs}
dkll-server    | 2019/06/14 03:51:20.026 [DEBUG] {mongo/server.go:56 mongo.NewServer} initial mongo delay=10
dkll-server    | 2019/06/14 03:51:20 [DEBUG] server mode activated master-6e2ca72-
dkll-server    | 2019/06/14 03:51:20 [INFO] backup files location /srv/logs
mongo-dkll_1   |
mongo-dkll_1   | error: missing 'MONGO_INITDB_ROOT_USERNAME' or 'MONGO_INITDB_ROOT_PASSWORD'
mongo-dkll_1   |        both must be specified for a user to be created
mongo-dkll_1   |
dkll_mongo-dkll_1 exited with code 1
dkll_mongo-dkll_1 exited with code 1
dkll-server    | 2019/06/14 03:51:30.026 [DEBUG] {mongo/server.go:60 mongo.NewServer} dial mongo [mongo-dkll], ssl=false
dkll_mongo-dkll_1 exited with code 1
dkll_mongo-dkll_1 exited with code 1
dkll-server    | 2019/06/14 03:51:36.268 [ERROR] {app/main.go:61 main.main} server failed, can't connect to mongo, no reachable servers
dkll-server    | 2019/06/14 03:51:36.268 [ERROR] {app/main.go:61 main.main} server failed, can't connect to mongo, no reachable servers
dkll_mongo-dkll_1 exited with code 1
dkll_mongo-dkll_1 exited with code 1
dkll-server    | 2019/06/14 03:51:49.850 [DEBUG] {mongo/server.go:60 mongo.NewServer} dial mongo [mongo-dkll], ssl=false
dkll_mongo-dkll_1 exited with code 1
dkll-server    | 2019/06/14 03:51:59.688 [ERROR] {app/main.go:61 main.main} server failed, can't connect to mongo, no reachable servers
dkll-server    | 2019/06/14 03:51:59.688 [ERROR] {app/main.go:61 main.main} server failed, can't connect to mongo, no reachable servers
dkll-server exited with code 1

Maybe add demo.env file with a default value or set default value directly into compose-demo.yml. Or just add a step with settings up into README.

Add streaming api

The new API method will be similar to /find but instead of sending the current result only will stream results back and performing updates check internally. Should be limited by query-defined timeout

The method could be useful for follow-mode and will minimize the number of http calls sent by clients

dkll client fails on "can't get data"

the client shouldn't fail is such a case but has to continue to try endlessly. This can be a valid situation, i.e. no new log messages.

example:

dkll client --api=http://example.com:82/v1 -f -h n3.example.com
2019/08/04 12:07:16.775 [ERROR] client failed, can't get data for request hosts=[n31.example.com], containers=[], excludes=[], max=0, last-id=: Post http://example.com:82/v1/find: http: ContentLength=110 with Body length 0

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.