// GetRealtimeUsec gets the realtime (wallclock) timestamp of the current // journal entry. func (j *Journal) GetRealtimeUsec() (uint64, error) { var usec C.uint64_t sd_journal_get_realtime_usec, err := j.getFunction("sd_journal_get_realtime_usec") if err != nil { return 0, err } j.mu.Lock() r := C.my_sd_journal_get_realtime_usec(sd_journal_get_realtime_usec, j.cjournal, &usec) j.mu.Unlock() if r < 0 { return 0, fmt.Errorf("error getting timestamp for entry: %d", syscall.Errno(-r)) } return uint64(usec), nil }
// GetEntry returns a full representation of a journal entry with // all key-value pairs of data as well as address fields (cursor, realtime // timestamp and monotonic timestamp) func (j *Journal) GetEntry() (*JournalEntry, error) { sd_journal_get_realtime_usec, err := getFunction("sd_journal_get_realtime_usec") if err != nil { return nil, err } sd_journal_get_monotonic_usec, err := getFunction("sd_journal_get_monotonic_usec") if err != nil { return nil, err } sd_journal_get_cursor, err := getFunction("sd_journal_get_cursor") if err != nil { return nil, err } sd_journal_restart_data, err := getFunction("sd_journal_restart_data") if err != nil { return nil, err } sd_journal_enumerate_data, err := getFunction("sd_journal_enumerate_data") if err != nil { return nil, err } j.mu.Lock() defer j.mu.Unlock() var r C.int entry := &JournalEntry{Fields: make(map[string]string)} var realtimeUsec C.uint64_t r = C.my_sd_journal_get_realtime_usec(sd_journal_get_realtime_usec, j.cjournal, &realtimeUsec) if r < 0 { return nil, fmt.Errorf("failed to get realtime timestamp: %d", syscall.Errno(-r)) } entry.RealtimeTimestamp = uint64(realtimeUsec) var monotonicUsec C.uint64_t var boot_id C.sd_id128_t r = C.my_sd_journal_get_monotonic_usec(sd_journal_get_monotonic_usec, j.cjournal, &monotonicUsec, &boot_id) if r < 0 { return nil, fmt.Errorf("failed to get monotonic timestamp: %d", syscall.Errno(-r)) } entry.MonotonicTimestamp = uint64(monotonicUsec) var c *C.char // since the pointer is mutated by sd_journal_get_cursor, need to wait // until after the call to free the memory r = C.my_sd_journal_get_cursor(sd_journal_get_cursor, j.cjournal, &c) defer C.free(unsafe.Pointer(c)) if r < 0 { return nil, fmt.Errorf("failed to get cursor: %d", syscall.Errno(-r)) } entry.Cursor = C.GoString(c) // Implements the JOURNAL_FOREACH_DATA_RETVAL macro from journal-internal.h var d unsafe.Pointer var l C.size_t C.my_sd_journal_restart_data(sd_journal_restart_data, j.cjournal) for { r = C.my_sd_journal_enumerate_data(sd_journal_enumerate_data, j.cjournal, &d, &l) if r == 0 { break } if r < 0 { return nil, fmt.Errorf("failed to read message field: %d", syscall.Errno(-r)) } msg := C.GoStringN((*C.char)(d), C.int(l)) kv := strings.SplitN(msg, "=", 2) if len(kv) < 2 { return nil, fmt.Errorf("failed to parse field") } entry.Fields[kv[0]] = kv[1] } return entry, nil }