2525package sdjournal
2626
2727// #include <systemd/sd-journal.h>
28+ // #include <systemd/sd-id128.h>
2829// #include <stdlib.h>
2930// #include <syslog.h>
3031//
@@ -182,6 +183,15 @@ package sdjournal
182183// }
183184//
184185// int
186+ // my_sd_journal_get_monotonic_usec(void *f, sd_journal *j, uint64_t *usec, sd_id128_t *boot_id)
187+ // {
188+ // int (*sd_journal_get_monotonic_usec)(sd_journal *, uint64_t *, sd_id128_t *);
189+ //
190+ // sd_journal_get_monotonic_usec = f;
191+ // return sd_journal_get_monotonic_usec(j, usec, boot_id);
192+ // }
193+ //
194+ // int
185195// my_sd_journal_seek_head(void *f, sd_journal *j)
186196// {
187197// int (*sd_journal_seek_head)(sd_journal *);
@@ -227,6 +237,24 @@ package sdjournal
227237// return sd_journal_wait(j, timeout_usec);
228238// }
229239//
240+ // void
241+ // my_sd_journal_restart_data(void *f, sd_journal *j)
242+ // {
243+ // void (*sd_journal_restart_data)(sd_journal *);
244+ //
245+ // sd_journal_restart_data = f;
246+ // sd_journal_restart_data(j);
247+ // }
248+ //
249+ // int
250+ // my_sd_journal_enumerate_data(void *f, sd_journal *j, const void **data, size_t *length)
251+ // {
252+ // int (*sd_journal_enumerate_data)(sd_journal *, const void **, size_t *);
253+ //
254+ // sd_journal_enumerate_data = f;
255+ // return sd_journal_enumerate_data(j, data, length);
256+ // }
257+ //
230258import "C"
231259import (
232260 "fmt"
@@ -245,15 +273,45 @@ var libsystemdFunctions = map[string]unsafe.Pointer{}
245273// Journal entry field strings which correspond to:
246274// http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html
247275const (
248- SD_JOURNAL_FIELD_SYSTEMD_UNIT = "_SYSTEMD_UNIT"
249- SD_JOURNAL_FIELD_SYSLOG_IDENTIFIER = "SYSLOG_IDENTIFIER"
276+ // User Journal Fields
250277 SD_JOURNAL_FIELD_MESSAGE = "MESSAGE"
251- SD_JOURNAL_FIELD_PID = "_PID"
252- SD_JOURNAL_FIELD_UID = "_UID"
253- SD_JOURNAL_FIELD_GID = "_GID"
254- SD_JOURNAL_FIELD_HOSTNAME = "_HOSTNAME"
255- SD_JOURNAL_FIELD_MACHINE_ID = "_MACHINE_ID"
256- SD_JOURNAL_FIELD_TRANSPORT = "_TRANSPORT"
278+ SD_JOURNAL_FIELD_MESSAGE_ID = "MESSAGE_ID"
279+ SD_JOURNAL_FIELD_PRIORITY = "PRIORITY"
280+ SD_JOURNAL_FIELD_CODE_FILE = "CODE_FILE"
281+ SD_JOURNAL_FIELD_CODE_LINE = "CODE_LINE"
282+ SD_JOURNAL_FIELD_CODE_FUNC = "CODE_FUNC"
283+ SD_JOURNAL_FIELD_ERRNO = "ERRNO"
284+ SD_JOURNAL_FIELD_SYSLOG_FACILITY = "SYSLOG_FACILITY"
285+ SD_JOURNAL_FIELD_SYSLOG_IDENTIFIER = "SYSLOG_IDENTIFIER"
286+ SD_JOURNAL_FIELD_SYSLOG_PID = "SYSLOG_PID"
287+
288+ // Trusted Journal Fields
289+ SD_JOURNAL_FIELD_PID = "_PID"
290+ SD_JOURNAL_FIELD_UID = "_UID"
291+ SD_JOURNAL_FIELD_GID = "_GID"
292+ SD_JOURNAL_FIELD_COMM = "_COMM"
293+ SD_JOURNAL_FIELD_EXE = "_EXE"
294+ SD_JOURNAL_FIELD_CMDLINE = "_CMDLINE"
295+ SD_JOURNAL_FIELD_CAP_EFFECTIVE = "_CAP_EFFECTIVE"
296+ SD_JOURNAL_FIELD_AUDIT_SESSION = "_AUDIT_SESSION"
297+ SD_JOURNAL_FIELD_AUDIT_LOGINUID = "_AUDIT_LOGINUID"
298+ SD_JOURNAL_FIELD_SYSTEMD_CGROUP = "_SYSTEMD_CGROUP"
299+ SD_JOURNAL_FIELD_SYSTEMD_SESSION = "_SYSTEMD_SESSION"
300+ SD_JOURNAL_FIELD_SYSTEMD_UNIT = "_SYSTEMD_UNIT"
301+ SD_JOURNAL_FIELD_SYSTEMD_USER_UNIT = "_SYSTEMD_USER_UNIT"
302+ SD_JOURNAL_FIELD_SYSTEMD_OWNER_UID = "_SYSTEMD_OWNER_UID"
303+ SD_JOURNAL_FIELD_SYSTEMD_SLICE = "_SYSTEMD_SLICE"
304+ SD_JOURNAL_FIELD_SELINUX_CONTEXT = "_SELINUX_CONTEXT"
305+ SD_JOURNAL_FIELD_SOURCE_REALTIME_TIMESTAMP = "_SOURCE_REALTIME_TIMESTAMP"
306+ SD_JOURNAL_FIELD_BOOT_ID = "_BOOT_ID"
307+ SD_JOURNAL_FIELD_MACHINE_ID = "_MACHINE_ID"
308+ SD_JOURNAL_FIELD_HOSTNAME = "_HOSTNAME"
309+ SD_JOURNAL_FIELD_TRANSPORT = "_TRANSPORT"
310+
311+ // Address Fields
312+ SD_JOURNAL_FIELD_CURSOR = "__CURSOR"
313+ SD_JOURNAL_FIELD_REALTIME_TIMESTAMP = "__REALTIME_TIMESTAMP"
314+ SD_JOURNAL_FIELD_MONOTONIC_TIMESTAMP = "__MONOTONIC_TIMESTAMP"
257315)
258316
259317// Journal event constants
@@ -288,6 +346,14 @@ type Journal struct {
288346 lib * dlopen.LibHandle
289347}
290348
349+ // JournalEntry represents all fields of a journal entry plus address fields.
350+ type JournalEntry struct {
351+ Fields map [string ]string
352+ Cursor string
353+ RealtimeTimestamp uint64
354+ MonotonicTimestamp uint64
355+ }
356+
291357// Match is a convenience wrapper to describe filters supplied to AddMatch.
292358type Match struct {
293359 Field string
@@ -583,6 +649,93 @@ func (j *Journal) GetDataValue(field string) (string, error) {
583649 return strings .SplitN (val , "=" , 2 )[1 ], nil
584650}
585651
652+ // GetEntry returns a full representation of a journal entry with
653+ // all key-value pairs of data as well as address fields (cursor, realtime
654+ // timestamp and monotonic timestamp)
655+ func (j * Journal ) GetEntry () (* JournalEntry , error ) {
656+ sd_journal_get_realtime_usec , err := j .getFunction ("sd_journal_get_realtime_usec" )
657+ if err != nil {
658+ return nil , err
659+ }
660+
661+ sd_journal_get_monotonic_usec , err := j .getFunction ("sd_journal_get_monotonic_usec" )
662+ if err != nil {
663+ return nil , err
664+ }
665+
666+ sd_journal_get_cursor , err := j .getFunction ("sd_journal_get_cursor" )
667+ if err != nil {
668+ return nil , err
669+ }
670+
671+ sd_journal_restart_data , err := j .getFunction ("sd_journal_restart_data" )
672+ if err != nil {
673+ return nil , err
674+ }
675+
676+ sd_journal_enumerate_data , err := j .getFunction ("sd_journal_enumerate_data" )
677+ if err != nil {
678+ return nil , err
679+ }
680+
681+ j .mu .Lock ()
682+ defer j .mu .Unlock ()
683+
684+ var r C.int
685+ entry := & JournalEntry {Fields : make (map [string ]string )}
686+
687+ var realtimeUsec C.uint64_t
688+ r = C .my_sd_journal_get_realtime_usec (sd_journal_get_realtime_usec , j .cjournal , & realtimeUsec )
689+ if r < 0 {
690+ return nil , fmt .Errorf ("failed to get realtime timestamp: %d" , syscall .Errno (- r ))
691+ }
692+
693+ entry .RealtimeTimestamp = uint64 (realtimeUsec )
694+
695+ var monotonicUsec C.uint64_t
696+ var boot_id C.sd_id128_t
697+
698+ r = C .my_sd_journal_get_monotonic_usec (sd_journal_get_monotonic_usec , j .cjournal , & monotonicUsec , & boot_id )
699+ if r < 0 {
700+ return nil , fmt .Errorf ("failed to get monotonic timestamp: %d" , syscall .Errno (- r ))
701+ }
702+
703+ entry .MonotonicTimestamp = uint64 (monotonicUsec )
704+
705+ var c * C.char
706+ r = C .my_sd_journal_get_cursor (sd_journal_get_cursor , j .cjournal , & c )
707+ if r < 0 {
708+ return nil , fmt .Errorf ("failed to get cursor: %d" , syscall .Errno (- r ))
709+ }
710+
711+ entry .Cursor = C .GoString (c )
712+
713+ // Implements the JOURNAL_FOREACH_DATA_RETVAL macro from journal-internal.h
714+ var d unsafe.Pointer
715+ var l C.size_t
716+ C .my_sd_journal_restart_data (sd_journal_restart_data , j .cjournal )
717+ for {
718+ r = C .my_sd_journal_enumerate_data (sd_journal_enumerate_data , j .cjournal , & d , & l )
719+ if r == 0 {
720+ break
721+ }
722+
723+ if r < 0 {
724+ return nil , fmt .Errorf ("failed to read message field: %d" , syscall .Errno (- r ))
725+ }
726+
727+ msg := C .GoStringN ((* C .char )(d ), C .int (l ))
728+ kv := strings .SplitN (msg , "=" , 2 )
729+ if len (kv ) < 2 {
730+ return nil , fmt .Errorf ("failed to parse field" )
731+ }
732+
733+ entry .Fields [kv [0 ]] = kv [1 ]
734+ }
735+
736+ return entry , nil
737+ }
738+
586739// SetDataThresold sets the data field size threshold for data returned by
587740// GetData. To retrieve the complete data fields this threshold should be
588741// turned off by setting it to 0, so that the library always returns the
@@ -619,7 +772,28 @@ func (j *Journal) GetRealtimeUsec() (uint64, error) {
619772 j .mu .Unlock ()
620773
621774 if r < 0 {
622- return 0 , fmt .Errorf ("error getting timestamp for entry: %d" , syscall .Errno (- r ))
775+ return 0 , fmt .Errorf ("failed to get realtime timestamp: %d" , syscall .Errno (- r ))
776+ }
777+
778+ return uint64 (usec ), nil
779+ }
780+
781+ // GetMonotonicUsec gets the monotonic timestamp of the current journal entry.
782+ func (j * Journal ) GetMonotonicUsec () (uint64 , error ) {
783+ var usec C.uint64_t
784+ var boot_id C.sd_id128_t
785+
786+ sd_journal_get_monotonic_usec , err := j .getFunction ("sd_journal_get_monotonic_usec" )
787+ if err != nil {
788+ return 0 , err
789+ }
790+
791+ j .mu .Lock ()
792+ r := C .my_sd_journal_get_monotonic_usec (sd_journal_get_monotonic_usec , j .cjournal , & usec , & boot_id )
793+ j .mu .Unlock ()
794+
795+ if r < 0 {
796+ return 0 , fmt .Errorf ("failed to get monotonic timestamp: %d" , syscall .Errno (- r ))
623797 }
624798
625799 return uint64 (usec ), nil
0 commit comments