Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com>
| ... | ... |
@@ -505,6 +505,7 @@ __docker_complete_log_drivers() {
|
| 505 | 505 |
gelf |
| 506 | 506 |
journald |
| 507 | 507 |
json-file |
| 508 |
+ logentries |
|
| 508 | 509 |
none |
| 509 | 510 |
splunk |
| 510 | 511 |
syslog |
| ... | ... |
@@ -519,10 +520,11 @@ __docker_complete_log_options() {
|
| 519 | 519 |
local gelf_options="env gelf-address gelf-compression-level gelf-compression-type labels tag" |
| 520 | 520 |
local journald_options="env labels tag" |
| 521 | 521 |
local json_file_options="env labels max-file max-size" |
| 522 |
+ local logentries_options="logentries-token" |
|
| 522 | 523 |
local syslog_options="env labels syslog-address syslog-facility syslog-format syslog-tls-ca-cert syslog-tls-cert syslog-tls-key syslog-tls-skip-verify tag" |
| 523 | 524 |
local splunk_options="env labels splunk-caname splunk-capath splunk-format splunk-gzip splunk-gzip-level splunk-index splunk-insecureskipverify splunk-source splunk-sourcetype splunk-token splunk-url splunk-verify-connection tag" |
| 524 | 525 |
|
| 525 |
- local all_options="$fluentd_options $gcplogs_options $gelf_options $journald_options $json_file_options $syslog_options $splunk_options" |
|
| 526 |
+ local all_options="$fluentd_options $gcplogs_options $gelf_options $journald_options $logentries_options $json_file_options $syslog_options $splunk_options" |
|
| 526 | 527 |
|
| 527 | 528 |
case $(__docker_value_of_option --log-driver) in |
| 528 | 529 |
'') |
| ... | ... |
@@ -546,6 +548,9 @@ __docker_complete_log_options() {
|
| 546 | 546 |
json-file) |
| 547 | 547 |
COMPREPLY=( $( compgen -W "$json_file_options" -S = -- "$cur" ) ) |
| 548 | 548 |
;; |
| 549 |
+ logentries) |
|
| 550 |
+ COMPREPLY=( $( compgen -W "$logentries_options" -S = -- "$cur" ) ) |
|
| 551 |
+ ;; |
|
| 549 | 552 |
syslog) |
| 550 | 553 |
COMPREPLY=( $( compgen -W "$syslog_options" -S = -- "$cur" ) ) |
| 551 | 554 |
;; |
| ... | ... |
@@ -219,7 +219,7 @@ __docker_get_log_options() {
|
| 219 | 219 |
|
| 220 | 220 |
integer ret=1 |
| 221 | 221 |
local log_driver=${opt_args[--log-driver]:-"all"}
|
| 222 |
- local -a awslogs_options fluentd_options gelf_options journald_options json_file_options syslog_options splunk_options |
|
| 222 |
+ local -a awslogs_options fluentd_options gelf_options journald_options json_file_options logentries_options syslog_options splunk_options |
|
| 223 | 223 |
|
| 224 | 224 |
awslogs_options=("awslogs-region" "awslogs-group" "awslogs-stream")
|
| 225 | 225 |
fluentd_options=("env" "fluentd-address" "fluentd-async-connect" "fluentd-buffer-limit" "fluentd-retry-wait" "fluentd-max-retries" "labels" "tag")
|
| ... | ... |
@@ -227,6 +227,7 @@ __docker_get_log_options() {
|
| 227 | 227 |
gelf_options=("env" "gelf-address" "gelf-compression-level" "gelf-compression-type" "labels" "tag")
|
| 228 | 228 |
journald_options=("env" "labels" "tag")
|
| 229 | 229 |
json_file_options=("env" "labels" "max-file" "max-size")
|
| 230 |
+ logentries_options=("logentries-token")
|
|
| 230 | 231 |
syslog_options=("env" "labels" "syslog-address" "syslog-facility" "syslog-format" "syslog-tls-ca-cert" "syslog-tls-cert" "syslog-tls-key" "syslog-tls-skip-verify" "tag")
|
| 231 | 232 |
splunk_options=("env" "labels" "splunk-caname" "splunk-capath" "splunk-format" "splunk-gzip" "splunk-gzip-level" "splunk-index" "splunk-insecureskipverify" "splunk-source" "splunk-sourcetype" "splunk-token" "splunk-url" "splunk-verify-connection" "tag")
|
| 232 | 233 |
|
| ... | ... |
@@ -236,6 +237,7 @@ __docker_get_log_options() {
|
| 236 | 236 |
[[ $log_driver = (gelf|all) ]] && _describe -t gelf-options "gelf options" gelf_options "$@" && ret=0 |
| 237 | 237 |
[[ $log_driver = (journald|all) ]] && _describe -t journald-options "journald options" journald_options "$@" && ret=0 |
| 238 | 238 |
[[ $log_driver = (json-file|all) ]] && _describe -t json-file-options "json-file options" json_file_options "$@" && ret=0 |
| 239 |
+ [[ $log_driver = (logentries|all) ]] && _describe -t logentries-options "logentries options" logentries_options "$@" && ret=0 |
|
| 239 | 240 |
[[ $log_driver = (syslog|all) ]] && _describe -t syslog-options "syslog options" syslog_options "$@" && ret=0 |
| 240 | 241 |
[[ $log_driver = (splunk|all) ]] && _describe -t splunk-options "splunk options" splunk_options "$@" && ret=0 |
| 241 | 242 |
|
| 242 | 243 |
deleted file mode 100644 |
| ... | ... |
@@ -1,42 +0,0 @@ |
| 1 |
-<!--[metadata]> |
|
| 2 |
-+++ |
|
| 3 |
-aliases = ["/engine/reference/logging/logentries/"] |
|
| 4 |
-title = "Logentries logging driver" |
|
| 5 |
-description = "Describes how to use the Logentries logging driver." |
|
| 6 |
-keywords = ["logentries, docker, logging, driver"] |
|
| 7 |
-[menu.main] |
|
| 8 |
-parent = "smn_logging" |
|
| 9 |
-weight = 2 |
|
| 10 |
-+++ |
|
| 11 |
-<![end-metadata]--> |
|
| 12 |
- |
|
| 13 |
-# Logentries logging driver |
|
| 14 |
- |
|
| 15 |
-The `logentries` logging driver sends container logs to the Logentries server. |
|
| 16 |
- |
|
| 17 |
-## Usage |
|
| 18 |
- |
|
| 19 |
-You can configure the default logging driver by passing the `--log-driver` |
|
| 20 |
-option to the Docker daemon: |
|
| 21 |
- |
|
| 22 |
- docker daemon --log-driver=logentries |
|
| 23 |
- |
|
| 24 |
-You can set the logging driver for a specific container by using the |
|
| 25 |
-`--log-driver` option to `docker run`: |
|
| 26 |
- |
|
| 27 |
- docker run --log-driver=logentries ... |
|
| 28 |
- |
|
| 29 |
-## Logentries options |
|
| 30 |
- |
|
| 31 |
-You can use the `--log-opt NAME=VALUE` flag to specify these additional |
|
| 32 |
-Logentries logging driver options: |
|
| 33 |
- |
|
| 34 |
-| Option | Required | Description | |
|
| 35 |
-|-----------------------------|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |
|
| 36 |
-| `logentries-token` | required | Logentries token. | |
|
| 37 |
- |
|
| 38 |
-An example usage would be somethig like: |
|
| 39 |
- |
|
| 40 |
- docker run --log-driver=logentries \ |
|
| 41 |
- --log-opt logentries-token=176FCEBF-4CF5-4EDF-91BC-703796522D20 \ |
|
| 42 |
- your/application |
| ... | ... |
@@ -131,6 +131,9 @@ clone git github.com/aws/aws-sdk-go v1.1.30 |
| 131 | 131 |
clone git github.com/go-ini/ini 060d7da055ba6ec5ea7a31f116332fe5efa04ce0 |
| 132 | 132 |
clone git github.com/jmespath/go-jmespath 0b12d6b521d83fc7f755e7cfc1b1fbdd35a01a74 |
| 133 | 133 |
|
| 134 |
+# logentries |
|
| 135 |
+clone git github.com/bsphere/le_go d3308aafe090956bc89a65f0769f58251a1b4f03 |
|
| 136 |
+ |
|
| 134 | 137 |
# gcplogs deps |
| 135 | 138 |
clone git golang.org/x/oauth2 2baa8a1b9338cf13d9eeb27696d761155fa480be https://github.com/golang/oauth2.git |
| 136 | 139 |
clone git google.golang.org/api dc6d2353af16e2a2b0ff6986af051d473a4ed468 https://code.googlesource.com/google-api-go-client |
| 137 | 140 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,23 @@ |
| 0 |
+# Compiled Object files, Static and Dynamic libs (Shared Objects) |
|
| 1 |
+*.o |
|
| 2 |
+*.a |
|
| 3 |
+*.so |
|
| 4 |
+ |
|
| 5 |
+# Folders |
|
| 6 |
+_obj |
|
| 7 |
+_test |
|
| 8 |
+ |
|
| 9 |
+# Architecture specific extensions/prefixes |
|
| 10 |
+*.[568vq] |
|
| 11 |
+[568vq].out |
|
| 12 |
+ |
|
| 13 |
+*.cgo1.go |
|
| 14 |
+*.cgo2.c |
|
| 15 |
+_cgo_defun.c |
|
| 16 |
+_cgo_gotypes.go |
|
| 17 |
+_cgo_export.* |
|
| 18 |
+ |
|
| 19 |
+_testmain.go |
|
| 20 |
+ |
|
| 21 |
+*.exe |
|
| 22 |
+*.test |
| 1 | 5 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,37 @@ |
| 0 |
+le_go |
|
| 1 |
+===== |
|
| 2 |
+ |
|
| 3 |
+Golang client library for logentries.com |
|
| 4 |
+ |
|
| 5 |
+It is compatible with http://golang.org/pkg/log/#Logger |
|
| 6 |
+and also implements http://golang.org/pkg/io/#Writer |
|
| 7 |
+ |
|
| 8 |
+[](https://godoc.org/github.com/bsphere/le_go) |
|
| 9 |
+ |
|
| 10 |
+[](https://travis-ci.org/bsphere/le_go) |
|
| 11 |
+ |
|
| 12 |
+Usage |
|
| 13 |
+----- |
|
| 14 |
+Add a new manual TCP token log at [logentries.com](https://logentries.com/quick-start/) and copy the [token](https://logentries.com/doc/input-token/). |
|
| 15 |
+ |
|
| 16 |
+Installation: `go get github.com/bsphere/le_go` |
|
| 17 |
+ |
|
| 18 |
+**Note:** The Logger is blocking, it can be easily run in a goroutine by calling `go le.Println(...)` |
|
| 19 |
+ |
|
| 20 |
+```go |
|
| 21 |
+package main |
|
| 22 |
+ |
|
| 23 |
+import "github.com/bsphere/le_go" |
|
| 24 |
+ |
|
| 25 |
+func main() {
|
|
| 26 |
+ le, err := le_go.Connect("XXXX-XXXX-XXXX-XXXX") // replace with token
|
|
| 27 |
+ if err != nil {
|
|
| 28 |
+ panic(err) |
|
| 29 |
+ } |
|
| 30 |
+ |
|
| 31 |
+ defer le.Close() |
|
| 32 |
+ |
|
| 33 |
+ le.Println("another test message")
|
|
| 34 |
+} |
|
| 35 |
+``` |
|
| 36 |
+ |
| 0 | 37 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,216 @@ |
| 0 |
+// Package le_go provides a Golang client library for logging to |
|
| 1 |
+// logentries.com over a TCP connection. |
|
| 2 |
+// |
|
| 3 |
+// it uses an access token for sending log events. |
|
| 4 |
+package le_go |
|
| 5 |
+ |
|
| 6 |
+import ( |
|
| 7 |
+ "crypto/tls" |
|
| 8 |
+ "fmt" |
|
| 9 |
+ "net" |
|
| 10 |
+ "os" |
|
| 11 |
+ "strings" |
|
| 12 |
+ "sync" |
|
| 13 |
+ "time" |
|
| 14 |
+) |
|
| 15 |
+ |
|
| 16 |
+// Logger represents a Logentries logger, |
|
| 17 |
+// it holds the open TCP connection, access token, prefix and flags. |
|
| 18 |
+// |
|
| 19 |
+// all Logger operations are thread safe and blocking, |
|
| 20 |
+// log operations can be invoked in a non-blocking way by calling them from |
|
| 21 |
+// a goroutine. |
|
| 22 |
+type Logger struct {
|
|
| 23 |
+ conn net.Conn |
|
| 24 |
+ flag int |
|
| 25 |
+ mu sync.Mutex |
|
| 26 |
+ prefix string |
|
| 27 |
+ token string |
|
| 28 |
+ buf []byte |
|
| 29 |
+} |
|
| 30 |
+ |
|
| 31 |
+const lineSep = "\n" |
|
| 32 |
+ |
|
| 33 |
+// Connect creates a new Logger instance and opens a TCP connection to |
|
| 34 |
+// logentries.com, |
|
| 35 |
+// The token can be generated at logentries.com by adding a new log, |
|
| 36 |
+// choosing manual configuration and token based TCP connection. |
|
| 37 |
+func Connect(token string) (*Logger, error) {
|
|
| 38 |
+ logger := Logger{
|
|
| 39 |
+ token: token, |
|
| 40 |
+ } |
|
| 41 |
+ |
|
| 42 |
+ if err := logger.openConnection(); err != nil {
|
|
| 43 |
+ return nil, err |
|
| 44 |
+ } |
|
| 45 |
+ |
|
| 46 |
+ return &logger, nil |
|
| 47 |
+} |
|
| 48 |
+ |
|
| 49 |
+// Close closes the TCP connection to logentries.com |
|
| 50 |
+func (logger *Logger) Close() error {
|
|
| 51 |
+ if logger.conn != nil {
|
|
| 52 |
+ return logger.conn.Close() |
|
| 53 |
+ } |
|
| 54 |
+ |
|
| 55 |
+ return nil |
|
| 56 |
+} |
|
| 57 |
+ |
|
| 58 |
+// Opens a TCP connection to logentries.com |
|
| 59 |
+func (logger *Logger) openConnection() error {
|
|
| 60 |
+ conn, err := tls.Dial("tcp", "data.logentries.com:443", &tls.Config{})
|
|
| 61 |
+ if err != nil {
|
|
| 62 |
+ return err |
|
| 63 |
+ } |
|
| 64 |
+ logger.conn = conn |
|
| 65 |
+ return nil |
|
| 66 |
+} |
|
| 67 |
+ |
|
| 68 |
+// It returns if the TCP connection to logentries.com is open |
|
| 69 |
+func (logger *Logger) isOpenConnection() bool {
|
|
| 70 |
+ if logger.conn == nil {
|
|
| 71 |
+ return false |
|
| 72 |
+ } |
|
| 73 |
+ |
|
| 74 |
+ buf := make([]byte, 1) |
|
| 75 |
+ |
|
| 76 |
+ logger.conn.SetReadDeadline(time.Now()) |
|
| 77 |
+ |
|
| 78 |
+ _, err := logger.conn.Read(buf) |
|
| 79 |
+ |
|
| 80 |
+ switch err.(type) {
|
|
| 81 |
+ case net.Error: |
|
| 82 |
+ if err.(net.Error).Timeout() == true {
|
|
| 83 |
+ logger.conn.SetReadDeadline(time.Time{})
|
|
| 84 |
+ |
|
| 85 |
+ return true |
|
| 86 |
+ } |
|
| 87 |
+ } |
|
| 88 |
+ |
|
| 89 |
+ return false |
|
| 90 |
+} |
|
| 91 |
+ |
|
| 92 |
+// It ensures that the TCP connection to logentries.com is open. |
|
| 93 |
+// If the connection is closed, a new one is opened. |
|
| 94 |
+func (logger *Logger) ensureOpenConnection() error {
|
|
| 95 |
+ if !logger.isOpenConnection() {
|
|
| 96 |
+ if err := logger.openConnection(); err != nil {
|
|
| 97 |
+ return err |
|
| 98 |
+ } |
|
| 99 |
+ } |
|
| 100 |
+ |
|
| 101 |
+ return nil |
|
| 102 |
+} |
|
| 103 |
+ |
|
| 104 |
+// Fatal is same as Print() but calls to os.Exit(1) |
|
| 105 |
+func (logger *Logger) Fatal(v ...interface{}) {
|
|
| 106 |
+ logger.Output(2, fmt.Sprint(v...)) |
|
| 107 |
+ os.Exit(1) |
|
| 108 |
+} |
|
| 109 |
+ |
|
| 110 |
+// Fatalf is same as Printf() but calls to os.Exit(1) |
|
| 111 |
+func (logger *Logger) Fatalf(format string, v ...interface{}) {
|
|
| 112 |
+ logger.Output(2, fmt.Sprintf(format, v...)) |
|
| 113 |
+ os.Exit(1) |
|
| 114 |
+} |
|
| 115 |
+ |
|
| 116 |
+// Fatalln is same as Println() but calls to os.Exit(1) |
|
| 117 |
+func (logger *Logger) Fatalln(v ...interface{}) {
|
|
| 118 |
+ logger.Output(2, fmt.Sprintln(v...)) |
|
| 119 |
+ os.Exit(1) |
|
| 120 |
+} |
|
| 121 |
+ |
|
| 122 |
+// Flags returns the logger flags |
|
| 123 |
+func (logger *Logger) Flags() int {
|
|
| 124 |
+ return logger.flag |
|
| 125 |
+} |
|
| 126 |
+ |
|
| 127 |
+// Output does the actual writing to the TCP connection |
|
| 128 |
+func (logger *Logger) Output(calldepth int, s string) error {
|
|
| 129 |
+ _, err := logger.Write([]byte(s)) |
|
| 130 |
+ |
|
| 131 |
+ return err |
|
| 132 |
+} |
|
| 133 |
+ |
|
| 134 |
+// Panic is same as Print() but calls to panic |
|
| 135 |
+func (logger *Logger) Panic(v ...interface{}) {
|
|
| 136 |
+ s := fmt.Sprint(v...) |
|
| 137 |
+ logger.Output(2, s) |
|
| 138 |
+ panic(s) |
|
| 139 |
+} |
|
| 140 |
+ |
|
| 141 |
+// Panicf is same as Printf() but calls to panic |
|
| 142 |
+func (logger *Logger) Panicf(format string, v ...interface{}) {
|
|
| 143 |
+ s := fmt.Sprintf(format, v...) |
|
| 144 |
+ logger.Output(2, s) |
|
| 145 |
+ panic(s) |
|
| 146 |
+} |
|
| 147 |
+ |
|
| 148 |
+// Panicln is same as Println() but calls to panic |
|
| 149 |
+func (logger *Logger) Panicln(v ...interface{}) {
|
|
| 150 |
+ s := fmt.Sprintln(v...) |
|
| 151 |
+ logger.Output(2, s) |
|
| 152 |
+ panic(s) |
|
| 153 |
+} |
|
| 154 |
+ |
|
| 155 |
+// Prefix returns the logger prefix |
|
| 156 |
+func (logger *Logger) Prefix() string {
|
|
| 157 |
+ return logger.prefix |
|
| 158 |
+} |
|
| 159 |
+ |
|
| 160 |
+// Print logs a message |
|
| 161 |
+func (logger *Logger) Print(v ...interface{}) {
|
|
| 162 |
+ logger.Output(2, fmt.Sprint(v...)) |
|
| 163 |
+} |
|
| 164 |
+ |
|
| 165 |
+// Printf logs a formatted message |
|
| 166 |
+func (logger *Logger) Printf(format string, v ...interface{}) {
|
|
| 167 |
+ logger.Output(2, fmt.Sprintf(format, v...)) |
|
| 168 |
+} |
|
| 169 |
+ |
|
| 170 |
+// Println logs a message with a linebreak |
|
| 171 |
+func (logger *Logger) Println(v ...interface{}) {
|
|
| 172 |
+ logger.Output(2, fmt.Sprintln(v...)) |
|
| 173 |
+} |
|
| 174 |
+ |
|
| 175 |
+// SetFlags sets the logger flags |
|
| 176 |
+func (logger *Logger) SetFlags(flag int) {
|
|
| 177 |
+ logger.flag = flag |
|
| 178 |
+} |
|
| 179 |
+ |
|
| 180 |
+// SetPrefix sets the logger prefix |
|
| 181 |
+func (logger *Logger) SetPrefix(prefix string) {
|
|
| 182 |
+ logger.prefix = prefix |
|
| 183 |
+} |
|
| 184 |
+ |
|
| 185 |
+// Write writes a bytes array to the Logentries TCP connection, |
|
| 186 |
+// it adds the access token and prefix and also replaces |
|
| 187 |
+// line breaks with the unicode \u2028 character |
|
| 188 |
+func (logger *Logger) Write(p []byte) (n int, err error) {
|
|
| 189 |
+ if err := logger.ensureOpenConnection(); err != nil {
|
|
| 190 |
+ return 0, err |
|
| 191 |
+ } |
|
| 192 |
+ |
|
| 193 |
+ logger.mu.Lock() |
|
| 194 |
+ defer logger.mu.Unlock() |
|
| 195 |
+ |
|
| 196 |
+ logger.makeBuf(p) |
|
| 197 |
+ |
|
| 198 |
+ return logger.conn.Write(logger.buf) |
|
| 199 |
+} |
|
| 200 |
+ |
|
| 201 |
+// makeBuf constructs the logger buffer |
|
| 202 |
+// it is not safe to be used from within multiple concurrent goroutines |
|
| 203 |
+func (logger *Logger) makeBuf(p []byte) {
|
|
| 204 |
+ count := strings.Count(string(p), lineSep) |
|
| 205 |
+ p = []byte(strings.Replace(string(p), lineSep, "\u2028", count-1)) |
|
| 206 |
+ |
|
| 207 |
+ logger.buf = logger.buf[:0] |
|
| 208 |
+ logger.buf = append(logger.buf, (logger.token + " ")...) |
|
| 209 |
+ logger.buf = append(logger.buf, (logger.prefix + " ")...) |
|
| 210 |
+ logger.buf = append(logger.buf, p...) |
|
| 211 |
+ |
|
| 212 |
+ if !strings.HasSuffix(string(logger.buf), lineSep) {
|
|
| 213 |
+ logger.buf = append(logger.buf, (lineSep)...) |
|
| 214 |
+ } |
|
| 215 |
+} |