Browse code

Add support for reading journal extras and in UTC

When told to read additional attributes from logs that we've sent to the
journal, pull out all of the non-trusted, non-user fields that we didn't
hard-code ourselves. More of PR#20726 and PR#21889.

When reading entries in the journald log reader, set the time zone on
timestamps that we read to UTC, so that we send UTC values to the client
instead of values that are local to whatever timezone dockerd happens to
be running in.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com> (github: nalind)

Nalin Dahyabhai authored on 2016/04/15 04:21:42
Showing 1 changed files
... ...
@@ -50,6 +50,53 @@ package journald
50 50
 //	}
51 51
 //	return rc;
52 52
 //}
53
+//static int is_attribute_field(const char *msg, size_t length)
54
+//{
55
+//	const struct known_field {
56
+//		const char *name;
57
+//		size_t length;
58
+//	} fields[] = {
59
+//		{"MESSAGE", sizeof("MESSAGE") - 1},
60
+//		{"MESSAGE_ID", sizeof("MESSAGE_ID") - 1},
61
+//		{"PRIORITY", sizeof("PRIORITY") - 1},
62
+//		{"CODE_FILE", sizeof("CODE_FILE") - 1},
63
+//		{"CODE_LINE", sizeof("CODE_LINE") - 1},
64
+//		{"CODE_FUNC", sizeof("CODE_FUNC") - 1},
65
+//		{"ERRNO", sizeof("ERRNO") - 1},
66
+//		{"SYSLOG_FACILITY", sizeof("SYSLOG_FACILITY") - 1},
67
+//		{"SYSLOG_IDENTIFIER", sizeof("SYSLOG_IDENTIFIER") - 1},
68
+//		{"SYSLOG_PID", sizeof("SYSLOG_PID") - 1},
69
+//		{"CONTAINER_NAME", sizeof("CONTAINER_NAME") - 1},
70
+//		{"CONTAINER_ID", sizeof("CONTAINER_ID") - 1},
71
+//		{"CONTAINER_ID_FULL", sizeof("CONTAINER_ID_FULL") - 1},
72
+//		{"CONTAINER_TAG", sizeof("CONTAINER_TAG") - 1},
73
+//	};
74
+//	unsigned int i;
75
+//	void *p;
76
+//	if ((length < 1) || (msg[0] == '_') || ((p = memchr(msg, '=', length)) == NULL)) {
77
+//		return -1;
78
+//	}
79
+//	length = ((const char *) p) - msg;
80
+//	for (i = 0; i < sizeof(fields) / sizeof(fields[0]); i++) {
81
+//		if ((fields[i].length == length) && (memcmp(fields[i].name, msg, length) == 0)) {
82
+//			return -1;
83
+//		}
84
+//	}
85
+//	return 0;
86
+//}
87
+//static int get_attribute_field(sd_journal *j, const char **msg, size_t *length)
88
+//{
89
+//	int rc;
90
+//	*msg = NULL;
91
+//	*length = 0;
92
+//	while ((rc = sd_journal_enumerate_data(j, (const void **) msg, length)) > 0) {
93
+//		if (is_attribute_field(*msg, *length) == 0) {
94
+//			break;
95
+//		}
96
+//		rc = -ENOENT;
97
+//	}
98
+//	return rc;
99
+//}
53 100
 //static int wait_for_data_or_close(sd_journal *j, int pipefd)
54 101
 //{
55 102
 //	struct pollfd fds[2];
... ...
@@ -98,6 +145,7 @@ import "C"
98 98
 
99 99
 import (
100 100
 	"fmt"
101
+	"strings"
101 102
 	"time"
102 103
 	"unsafe"
103 104
 
... ...
@@ -116,7 +164,7 @@ func (s *journald) Close() error {
116 116
 }
117 117
 
118 118
 func (s *journald) drainJournal(logWatcher *logger.LogWatcher, config logger.ReadConfig, j *C.sd_journal, oldCursor string) string {
119
-	var msg, cursor *C.char
119
+	var msg, data, cursor *C.char
120 120
 	var length C.size_t
121 121
 	var stamp C.uint64_t
122 122
 	var priority C.int
... ...
@@ -156,8 +204,23 @@ drain:
156 156
 			} else if priority == C.int(journal.PriInfo) {
157 157
 				source = "stdout"
158 158
 			}
159
+			// Retrieve the values of any variables we're adding to the journal.
160
+			attrs := make(map[string]string)
161
+			C.sd_journal_restart_data(j)
162
+			for C.get_attribute_field(j, &data, &length) > C.int(0) {
163
+				kv := strings.SplitN(C.GoStringN(data, C.int(length)), "=", 2)
164
+				attrs[kv[0]] = kv[1]
165
+			}
166
+			if len(attrs) == 0 {
167
+				attrs = nil
168
+			}
159 169
 			// Send the log message.
160
-			logWatcher.Msg <- &logger.Message{Line: line, Source: source, Timestamp: timestamp}
170
+			logWatcher.Msg <- &logger.Message{
171
+				Line:      line,
172
+				Source:    source,
173
+				Timestamp: timestamp.In(time.UTC),
174
+				Attrs:     attrs,
175
+			}
161 176
 		}
162 177
 		// If we're at the end of the journal, we're done (for now).
163 178
 		if C.sd_journal_next(j) <= 0 {