Skip to content

Commit 361a582

Browse files
committed
Add new logging driver: fluentd
Signed-off-by: TAGOMORI Satoshi <tagomoris@gmail.com>
1 parent dd40889 commit 361a582

33 files changed

+7763
-3
lines changed

daemon/logdrivers_linux.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package daemon
33
// Importing packages here only to make sure their init gets called and
44
// therefore they register themselves to the logdriver factory.
55
import (
6+
_ "github.com/docker/docker/daemon/logger/fluentd"
67
_ "github.com/docker/docker/daemon/logger/gelf"
78
_ "github.com/docker/docker/daemon/logger/journald"
89
_ "github.com/docker/docker/daemon/logger/jsonfilelog"

daemon/logger/fluentd/fluentd.go

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package fluentd
2+
3+
import (
4+
"bytes"
5+
"io"
6+
"math"
7+
"net"
8+
"strconv"
9+
"strings"
10+
"text/template"
11+
12+
"github.com/Sirupsen/logrus"
13+
"github.com/docker/docker/daemon/logger"
14+
"github.com/fluent/fluent-logger-golang/fluent"
15+
)
16+
17+
type Fluentd struct {
18+
tag string
19+
containerID string
20+
containerName string
21+
writer *fluent.Fluent
22+
}
23+
24+
type Receiver struct {
25+
ID string
26+
FullID string
27+
Name string
28+
}
29+
30+
const (
31+
name = "fluentd"
32+
defaultHostName = "localhost"
33+
defaultPort = 24224
34+
defaultTagPrefix = "docker"
35+
)
36+
37+
func init() {
38+
if err := logger.RegisterLogDriver(name, New); err != nil {
39+
logrus.Fatal(err)
40+
}
41+
}
42+
43+
func parseConfig(ctx logger.Context) (string, int, string, error) {
44+
host := defaultHostName
45+
port := defaultPort
46+
tag := "docker." + ctx.ContainerID[:12]
47+
48+
config := ctx.Config
49+
50+
if address := config["fluentd-address"]; address != "" {
51+
if h, p, err := net.SplitHostPort(address); err != nil {
52+
if !strings.Contains(err.Error(), "missing port in address") {
53+
return "", 0, "", err
54+
}
55+
host = h
56+
} else {
57+
portnum, err := strconv.Atoi(p)
58+
if err != nil {
59+
return "", 0, "", err
60+
}
61+
host = h
62+
port = portnum
63+
}
64+
}
65+
66+
if config["fluentd-tag"] != "" {
67+
receiver := &Receiver{
68+
ID: ctx.ContainerID[:12],
69+
FullID: ctx.ContainerID,
70+
Name: ctx.ContainerName,
71+
}
72+
tmpl, err := template.New("tag").Parse(config["fluentd-tag"])
73+
if err != nil {
74+
return "", 0, "", err
75+
}
76+
buf := new(bytes.Buffer)
77+
if err := tmpl.Execute(buf, receiver); err != nil {
78+
return "", 0, "", err
79+
}
80+
tag = buf.String()
81+
}
82+
83+
return host, port, tag, nil
84+
}
85+
86+
func New(ctx logger.Context) (logger.Logger, error) {
87+
host, port, tag, err := parseConfig(ctx)
88+
if err != nil {
89+
return nil, err
90+
}
91+
logrus.Debugf("logging driver fluentd configured for container:%s, host:%s, port:%d, tag:%s.", ctx.ContainerID, host, port, tag)
92+
93+
// logger tries to recoonect 2**64 - 1 times
94+
// failed (and panic) after 204 years [ 1.5 ** (2**32 - 1) - 1 seconds]
95+
log, err := fluent.New(fluent.Config{FluentPort: port, FluentHost: host, RetryWait: 1000, MaxRetry: math.MaxUint32})
96+
if err != nil {
97+
return nil, err
98+
}
99+
return &Fluentd{
100+
tag: tag,
101+
containerID: ctx.ContainerID,
102+
containerName: ctx.ContainerName,
103+
writer: log,
104+
}, nil
105+
}
106+
107+
func (f *Fluentd) Log(msg *logger.Message) error {
108+
data := map[string]string{
109+
"container_id": f.containerID,
110+
"container_name": f.containerName,
111+
"source": msg.Source,
112+
"log": string(msg.Line),
113+
}
114+
// fluent-logger-golang buffers logs from failures and disconnections,
115+
// and these are transferred again automatically.
116+
return f.writer.PostWithTime(f.tag, msg.Timestamp, data)
117+
}
118+
119+
func (f *Fluentd) Close() error {
120+
return f.writer.Close()
121+
}
122+
123+
func (f *Fluentd) Name() string {
124+
return name
125+
}
126+
127+
func (s *Fluentd) GetReader() (io.Reader, error) {
128+
return nil, logger.ReadLogsNotSupported
129+
}

docs/reference/run.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,16 @@ container's logging driver. The following options are supported:
884884
driver. For detailed information on working with logging drivers, see
885885
[Configure a logging driver](reference/logging/).
886886

887+
#### Logging driver: fluentd
888+
889+
Fluentd logging driver for Docker. Writes log messages to fluentd (forward input). `docker logs`
890+
command is not available for this logging driver.
891+
892+
Some options are supported by specifying `--log-opt` as many as needed, like `--log-opt fluentd-address=localhost:24224`.
893+
894+
- `fluentd-address`: specify `host:port` to connect [localhost:24224]
895+
- `fluentd-tag`: specify tag for fluentd message, which interpret some markup, ex `{{.ID}}`, `{{.FullID}}` or `{{.Name}}` [docker.{{.ID}}]
896+
887897
## Overriding Dockerfile image defaults
888898

889899
When a developer builds an image from a [*Dockerfile*](/reference/builder)

hack/vendor.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,9 @@ clone git github.com/syndtr/gocapability 66ef2aa7a23ba682594e2b6f74cf40c0692b49f
4242
clone git github.com/golang/protobuf 655cdfa588ea
4343
clone git github.com/Graylog2/go-gelf 6c62a85f1d47a67f2a5144c0e745b325889a8120
4444

45+
clone git github.com/fluent/fluent-logger-golang v1.0.0
46+
# fluent-logger-golang deps
47+
clone git github.com/philhofer/fwd 899e4efba8eaa1fea74175308f3fae18ff3319fa
48+
clone git github.com/tinylib/msgp 75ee40d2601edf122ef667e2a07d600d4c44490c
49+
4550
clean

man/docker-create.1.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ two memory nodes.
155155
**--lxc-conf**=[]
156156
(lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"
157157

158-
**--log-driver**="|*json-file*|*syslog*|*journald*|*gelf*|*none*"
158+
**--log-driver**="|*json-file*|*syslog*|*journald*|*gelf*|*fluentd*|*none*"
159159
Logging driver for container. Default is defined by daemon `--log-driver` flag.
160160
**Warning**: `docker logs` command works only for `json-file` logging driver.
161161

man/docker-run.1.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ which interface and port to use.
252252
**--lxc-conf**=[]
253253
(lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"
254254

255-
**--log-driver**="|*json-file*|*syslog*|*journald*|*gelf*|*none*"
255+
**--log-driver**="|*json-file*|*syslog*|*journald*|*gelf*|*fluentd*|*none*"
256256
Logging driver for container. Default is defined by daemon `--log-driver` flag.
257257
**Warning**: `docker logs` command works only for `json-file` logging driver.
258258

man/docker.1.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ unix://[/path/to/socket] to use.
103103
**--label**="[]"
104104
Set key=value labels to the daemon (displayed in `docker info`)
105105

106-
**--log-driver**="*json-file*|*syslog*|*journald*|*gelf*|*none*"
106+
**--log-driver**="*json-file*|*syslog*|*journald*|*gelf*|*fluentd*|*none*"
107107
Default driver for container logs. Default is `json-file`.
108108
**Warning**: `docker logs` command works only for `json-file` logging driver.
109109

0 commit comments

Comments
 (0)