journal.go 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  1. // Copyright 2015 RedHat, Inc.
  2. // Copyright 2015 CoreOS, Inc.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. // Package sdjournal provides a low-level Go interface to the
  16. // systemd journal wrapped around the sd-journal C API.
  17. //
  18. // All public read methods map closely to the sd-journal API functions. See the
  19. // sd-journal.h documentation[1] for information about each function.
  20. //
  21. // To write to the journal, see the pure-Go "journal" package
  22. //
  23. // [1] http://www.freedesktop.org/software/systemd/man/sd-journal.html
  24. package sdjournal
  25. // #include <systemd/sd-journal.h>
  26. // #include <systemd/sd-id128.h>
  27. // #include <stdlib.h>
  28. // #include <syslog.h>
  29. //
  30. // int
  31. // my_sd_journal_open(void *f, sd_journal **ret, int flags)
  32. // {
  33. // int (*sd_journal_open)(sd_journal **, int);
  34. //
  35. // sd_journal_open = f;
  36. // return sd_journal_open(ret, flags);
  37. // }
  38. //
  39. // int
  40. // my_sd_journal_open_directory(void *f, sd_journal **ret, const char *path, int flags)
  41. // {
  42. // int (*sd_journal_open_directory)(sd_journal **, const char *, int);
  43. //
  44. // sd_journal_open_directory = f;
  45. // return sd_journal_open_directory(ret, path, flags);
  46. // }
  47. //
  48. // void
  49. // my_sd_journal_close(void *f, sd_journal *j)
  50. // {
  51. // int (*sd_journal_close)(sd_journal *);
  52. //
  53. // sd_journal_close = f;
  54. // sd_journal_close(j);
  55. // }
  56. //
  57. // int
  58. // my_sd_journal_get_usage(void *f, sd_journal *j, uint64_t *bytes)
  59. // {
  60. // int (*sd_journal_get_usage)(sd_journal *, uint64_t *);
  61. //
  62. // sd_journal_get_usage = f;
  63. // return sd_journal_get_usage(j, bytes);
  64. // }
  65. //
  66. // int
  67. // my_sd_journal_add_match(void *f, sd_journal *j, const void *data, size_t size)
  68. // {
  69. // int (*sd_journal_add_match)(sd_journal *, const void *, size_t);
  70. //
  71. // sd_journal_add_match = f;
  72. // return sd_journal_add_match(j, data, size);
  73. // }
  74. //
  75. // int
  76. // my_sd_journal_add_disjunction(void *f, sd_journal *j)
  77. // {
  78. // int (*sd_journal_add_disjunction)(sd_journal *);
  79. //
  80. // sd_journal_add_disjunction = f;
  81. // return sd_journal_add_disjunction(j);
  82. // }
  83. //
  84. // int
  85. // my_sd_journal_add_conjunction(void *f, sd_journal *j)
  86. // {
  87. // int (*sd_journal_add_conjunction)(sd_journal *);
  88. //
  89. // sd_journal_add_conjunction = f;
  90. // return sd_journal_add_conjunction(j);
  91. // }
  92. //
  93. // void
  94. // my_sd_journal_flush_matches(void *f, sd_journal *j)
  95. // {
  96. // int (*sd_journal_flush_matches)(sd_journal *);
  97. //
  98. // sd_journal_flush_matches = f;
  99. // sd_journal_flush_matches(j);
  100. // }
  101. //
  102. // int
  103. // my_sd_journal_next(void *f, sd_journal *j)
  104. // {
  105. // int (*sd_journal_next)(sd_journal *);
  106. //
  107. // sd_journal_next = f;
  108. // return sd_journal_next(j);
  109. // }
  110. //
  111. // int
  112. // my_sd_journal_next_skip(void *f, sd_journal *j, uint64_t skip)
  113. // {
  114. // int (*sd_journal_next_skip)(sd_journal *, uint64_t);
  115. //
  116. // sd_journal_next_skip = f;
  117. // return sd_journal_next_skip(j, skip);
  118. // }
  119. //
  120. // int
  121. // my_sd_journal_previous(void *f, sd_journal *j)
  122. // {
  123. // int (*sd_journal_previous)(sd_journal *);
  124. //
  125. // sd_journal_previous = f;
  126. // return sd_journal_previous(j);
  127. // }
  128. //
  129. // int
  130. // my_sd_journal_previous_skip(void *f, sd_journal *j, uint64_t skip)
  131. // {
  132. // int (*sd_journal_previous_skip)(sd_journal *, uint64_t);
  133. //
  134. // sd_journal_previous_skip = f;
  135. // return sd_journal_previous_skip(j, skip);
  136. // }
  137. //
  138. // int
  139. // my_sd_journal_get_data(void *f, sd_journal *j, const char *field, const void **data, size_t *length)
  140. // {
  141. // int (*sd_journal_get_data)(sd_journal *, const char *, const void **, size_t *);
  142. //
  143. // sd_journal_get_data = f;
  144. // return sd_journal_get_data(j, field, data, length);
  145. // }
  146. //
  147. // int
  148. // my_sd_journal_set_data_threshold(void *f, sd_journal *j, size_t sz)
  149. // {
  150. // int (*sd_journal_set_data_threshold)(sd_journal *, size_t);
  151. //
  152. // sd_journal_set_data_threshold = f;
  153. // return sd_journal_set_data_threshold(j, sz);
  154. // }
  155. //
  156. // int
  157. // my_sd_journal_get_cursor(void *f, sd_journal *j, char **cursor)
  158. // {
  159. // int (*sd_journal_get_cursor)(sd_journal *, char **);
  160. //
  161. // sd_journal_get_cursor = f;
  162. // return sd_journal_get_cursor(j, cursor);
  163. // }
  164. //
  165. // int
  166. // my_sd_journal_test_cursor(void *f, sd_journal *j, const char *cursor)
  167. // {
  168. // int (*sd_journal_test_cursor)(sd_journal *, const char *);
  169. //
  170. // sd_journal_test_cursor = f;
  171. // return sd_journal_test_cursor(j, cursor);
  172. // }
  173. //
  174. // int
  175. // my_sd_journal_get_realtime_usec(void *f, sd_journal *j, uint64_t *usec)
  176. // {
  177. // int (*sd_journal_get_realtime_usec)(sd_journal *, uint64_t *);
  178. //
  179. // sd_journal_get_realtime_usec = f;
  180. // return sd_journal_get_realtime_usec(j, usec);
  181. // }
  182. //
  183. // int
  184. // my_sd_journal_get_monotonic_usec(void *f, sd_journal *j, uint64_t *usec, sd_id128_t *boot_id)
  185. // {
  186. // int (*sd_journal_get_monotonic_usec)(sd_journal *, uint64_t *, sd_id128_t *);
  187. //
  188. // sd_journal_get_monotonic_usec = f;
  189. // return sd_journal_get_monotonic_usec(j, usec, boot_id);
  190. // }
  191. //
  192. // int
  193. // my_sd_journal_seek_head(void *f, sd_journal *j)
  194. // {
  195. // int (*sd_journal_seek_head)(sd_journal *);
  196. //
  197. // sd_journal_seek_head = f;
  198. // return sd_journal_seek_head(j);
  199. // }
  200. //
  201. // int
  202. // my_sd_journal_seek_tail(void *f, sd_journal *j)
  203. // {
  204. // int (*sd_journal_seek_tail)(sd_journal *);
  205. //
  206. // sd_journal_seek_tail = f;
  207. // return sd_journal_seek_tail(j);
  208. // }
  209. //
  210. //
  211. // int
  212. // my_sd_journal_seek_cursor(void *f, sd_journal *j, const char *cursor)
  213. // {
  214. // int (*sd_journal_seek_cursor)(sd_journal *, const char *);
  215. //
  216. // sd_journal_seek_cursor = f;
  217. // return sd_journal_seek_cursor(j, cursor);
  218. // }
  219. //
  220. // int
  221. // my_sd_journal_seek_realtime_usec(void *f, sd_journal *j, uint64_t usec)
  222. // {
  223. // int (*sd_journal_seek_realtime_usec)(sd_journal *, uint64_t);
  224. //
  225. // sd_journal_seek_realtime_usec = f;
  226. // return sd_journal_seek_realtime_usec(j, usec);
  227. // }
  228. //
  229. // int
  230. // my_sd_journal_wait(void *f, sd_journal *j, uint64_t timeout_usec)
  231. // {
  232. // int (*sd_journal_wait)(sd_journal *, uint64_t);
  233. //
  234. // sd_journal_wait = f;
  235. // return sd_journal_wait(j, timeout_usec);
  236. // }
  237. //
  238. // void
  239. // my_sd_journal_restart_data(void *f, sd_journal *j)
  240. // {
  241. // void (*sd_journal_restart_data)(sd_journal *);
  242. //
  243. // sd_journal_restart_data = f;
  244. // sd_journal_restart_data(j);
  245. // }
  246. //
  247. // int
  248. // my_sd_journal_enumerate_data(void *f, sd_journal *j, const void **data, size_t *length)
  249. // {
  250. // int (*sd_journal_enumerate_data)(sd_journal *, const void **, size_t *);
  251. //
  252. // sd_journal_enumerate_data = f;
  253. // return sd_journal_enumerate_data(j, data, length);
  254. // }
  255. //
  256. // int
  257. // my_sd_journal_query_unique(void *f, sd_journal *j, const char *field)
  258. // {
  259. // int(*sd_journal_query_unique)(sd_journal *, const char *);
  260. //
  261. // sd_journal_query_unique = f;
  262. // return sd_journal_query_unique(j, field);
  263. // }
  264. //
  265. // int
  266. // my_sd_journal_enumerate_unique(void *f, sd_journal *j, const void **data, size_t *length)
  267. // {
  268. // int(*sd_journal_enumerate_unique)(sd_journal *, const void **, size_t *);
  269. //
  270. // sd_journal_enumerate_unique = f;
  271. // return sd_journal_enumerate_unique(j, data, length);
  272. // }
  273. //
  274. // void
  275. // my_sd_journal_restart_unique(void *f, sd_journal *j)
  276. // {
  277. // void(*sd_journal_restart_unique)(sd_journal *);
  278. //
  279. // sd_journal_restart_unique = f;
  280. // sd_journal_restart_unique(j);
  281. // }
  282. //
  283. import "C"
  284. import (
  285. "bytes"
  286. "fmt"
  287. "strings"
  288. "sync"
  289. "syscall"
  290. "time"
  291. "unsafe"
  292. )
  293. // Journal entry field strings which correspond to:
  294. // http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html
  295. const (
  296. // User Journal Fields
  297. SD_JOURNAL_FIELD_MESSAGE = "MESSAGE"
  298. SD_JOURNAL_FIELD_MESSAGE_ID = "MESSAGE_ID"
  299. SD_JOURNAL_FIELD_PRIORITY = "PRIORITY"
  300. SD_JOURNAL_FIELD_CODE_FILE = "CODE_FILE"
  301. SD_JOURNAL_FIELD_CODE_LINE = "CODE_LINE"
  302. SD_JOURNAL_FIELD_CODE_FUNC = "CODE_FUNC"
  303. SD_JOURNAL_FIELD_ERRNO = "ERRNO"
  304. SD_JOURNAL_FIELD_SYSLOG_FACILITY = "SYSLOG_FACILITY"
  305. SD_JOURNAL_FIELD_SYSLOG_IDENTIFIER = "SYSLOG_IDENTIFIER"
  306. SD_JOURNAL_FIELD_SYSLOG_PID = "SYSLOG_PID"
  307. // Trusted Journal Fields
  308. SD_JOURNAL_FIELD_PID = "_PID"
  309. SD_JOURNAL_FIELD_UID = "_UID"
  310. SD_JOURNAL_FIELD_GID = "_GID"
  311. SD_JOURNAL_FIELD_COMM = "_COMM"
  312. SD_JOURNAL_FIELD_EXE = "_EXE"
  313. SD_JOURNAL_FIELD_CMDLINE = "_CMDLINE"
  314. SD_JOURNAL_FIELD_CAP_EFFECTIVE = "_CAP_EFFECTIVE"
  315. SD_JOURNAL_FIELD_AUDIT_SESSION = "_AUDIT_SESSION"
  316. SD_JOURNAL_FIELD_AUDIT_LOGINUID = "_AUDIT_LOGINUID"
  317. SD_JOURNAL_FIELD_SYSTEMD_CGROUP = "_SYSTEMD_CGROUP"
  318. SD_JOURNAL_FIELD_SYSTEMD_SESSION = "_SYSTEMD_SESSION"
  319. SD_JOURNAL_FIELD_SYSTEMD_UNIT = "_SYSTEMD_UNIT"
  320. SD_JOURNAL_FIELD_SYSTEMD_USER_UNIT = "_SYSTEMD_USER_UNIT"
  321. SD_JOURNAL_FIELD_SYSTEMD_OWNER_UID = "_SYSTEMD_OWNER_UID"
  322. SD_JOURNAL_FIELD_SYSTEMD_SLICE = "_SYSTEMD_SLICE"
  323. SD_JOURNAL_FIELD_SELINUX_CONTEXT = "_SELINUX_CONTEXT"
  324. SD_JOURNAL_FIELD_SOURCE_REALTIME_TIMESTAMP = "_SOURCE_REALTIME_TIMESTAMP"
  325. SD_JOURNAL_FIELD_BOOT_ID = "_BOOT_ID"
  326. SD_JOURNAL_FIELD_MACHINE_ID = "_MACHINE_ID"
  327. SD_JOURNAL_FIELD_HOSTNAME = "_HOSTNAME"
  328. SD_JOURNAL_FIELD_TRANSPORT = "_TRANSPORT"
  329. // Address Fields
  330. SD_JOURNAL_FIELD_CURSOR = "__CURSOR"
  331. SD_JOURNAL_FIELD_REALTIME_TIMESTAMP = "__REALTIME_TIMESTAMP"
  332. SD_JOURNAL_FIELD_MONOTONIC_TIMESTAMP = "__MONOTONIC_TIMESTAMP"
  333. )
  334. // Journal event constants
  335. const (
  336. SD_JOURNAL_NOP = int(C.SD_JOURNAL_NOP)
  337. SD_JOURNAL_APPEND = int(C.SD_JOURNAL_APPEND)
  338. SD_JOURNAL_INVALIDATE = int(C.SD_JOURNAL_INVALIDATE)
  339. )
  340. const (
  341. // IndefiniteWait is a sentinel value that can be passed to
  342. // sdjournal.Wait() to signal an indefinite wait for new journal
  343. // events. It is implemented as the maximum value for a time.Duration:
  344. // https://github.com/golang/go/blob/e4dcf5c8c22d98ac9eac7b9b226596229624cb1d/src/time/time.go#L434
  345. IndefiniteWait time.Duration = 1<<63 - 1
  346. )
  347. // Journal is a Go wrapper of an sd_journal structure.
  348. type Journal struct {
  349. cjournal *C.sd_journal
  350. mu sync.Mutex
  351. }
  352. // JournalEntry represents all fields of a journal entry plus address fields.
  353. type JournalEntry struct {
  354. Fields map[string]string
  355. Cursor string
  356. RealtimeTimestamp uint64
  357. MonotonicTimestamp uint64
  358. }
  359. // Match is a convenience wrapper to describe filters supplied to AddMatch.
  360. type Match struct {
  361. Field string
  362. Value string
  363. }
  364. // String returns a string representation of a Match suitable for use with AddMatch.
  365. func (m *Match) String() string {
  366. return m.Field + "=" + m.Value
  367. }
  368. // NewJournal returns a new Journal instance pointing to the local journal
  369. func NewJournal() (j *Journal, err error) {
  370. j = &Journal{}
  371. sd_journal_open, err := getFunction("sd_journal_open")
  372. if err != nil {
  373. return nil, err
  374. }
  375. r := C.my_sd_journal_open(sd_journal_open, &j.cjournal, C.SD_JOURNAL_LOCAL_ONLY)
  376. if r < 0 {
  377. return nil, fmt.Errorf("failed to open journal: %d", syscall.Errno(-r))
  378. }
  379. return j, nil
  380. }
  381. // NewJournalFromDir returns a new Journal instance pointing to a journal residing
  382. // in a given directory. The supplied path may be relative or absolute; if
  383. // relative, it will be converted to an absolute path before being opened.
  384. func NewJournalFromDir(path string) (j *Journal, err error) {
  385. j = &Journal{}
  386. sd_journal_open_directory, err := getFunction("sd_journal_open_directory")
  387. if err != nil {
  388. return nil, err
  389. }
  390. p := C.CString(path)
  391. defer C.free(unsafe.Pointer(p))
  392. r := C.my_sd_journal_open_directory(sd_journal_open_directory, &j.cjournal, p, 0)
  393. if r < 0 {
  394. return nil, fmt.Errorf("failed to open journal in directory %q: %d", path, syscall.Errno(-r))
  395. }
  396. return j, nil
  397. }
  398. // Close closes a journal opened with NewJournal.
  399. func (j *Journal) Close() error {
  400. sd_journal_close, err := getFunction("sd_journal_close")
  401. if err != nil {
  402. return err
  403. }
  404. j.mu.Lock()
  405. C.my_sd_journal_close(sd_journal_close, j.cjournal)
  406. j.mu.Unlock()
  407. return nil
  408. }
  409. // AddMatch adds a match by which to filter the entries of the journal.
  410. func (j *Journal) AddMatch(match string) error {
  411. sd_journal_add_match, err := getFunction("sd_journal_add_match")
  412. if err != nil {
  413. return err
  414. }
  415. m := C.CString(match)
  416. defer C.free(unsafe.Pointer(m))
  417. j.mu.Lock()
  418. r := C.my_sd_journal_add_match(sd_journal_add_match, j.cjournal, unsafe.Pointer(m), C.size_t(len(match)))
  419. j.mu.Unlock()
  420. if r < 0 {
  421. return fmt.Errorf("failed to add match: %d", syscall.Errno(-r))
  422. }
  423. return nil
  424. }
  425. // AddDisjunction inserts a logical OR in the match list.
  426. func (j *Journal) AddDisjunction() error {
  427. sd_journal_add_disjunction, err := getFunction("sd_journal_add_disjunction")
  428. if err != nil {
  429. return err
  430. }
  431. j.mu.Lock()
  432. r := C.my_sd_journal_add_disjunction(sd_journal_add_disjunction, j.cjournal)
  433. j.mu.Unlock()
  434. if r < 0 {
  435. return fmt.Errorf("failed to add a disjunction in the match list: %d", syscall.Errno(-r))
  436. }
  437. return nil
  438. }
  439. // AddConjunction inserts a logical AND in the match list.
  440. func (j *Journal) AddConjunction() error {
  441. sd_journal_add_conjunction, err := getFunction("sd_journal_add_conjunction")
  442. if err != nil {
  443. return err
  444. }
  445. j.mu.Lock()
  446. r := C.my_sd_journal_add_conjunction(sd_journal_add_conjunction, j.cjournal)
  447. j.mu.Unlock()
  448. if r < 0 {
  449. return fmt.Errorf("failed to add a conjunction in the match list: %d", syscall.Errno(-r))
  450. }
  451. return nil
  452. }
  453. // FlushMatches flushes all matches, disjunctions and conjunctions.
  454. func (j *Journal) FlushMatches() {
  455. sd_journal_flush_matches, err := getFunction("sd_journal_flush_matches")
  456. if err != nil {
  457. return
  458. }
  459. j.mu.Lock()
  460. C.my_sd_journal_flush_matches(sd_journal_flush_matches, j.cjournal)
  461. j.mu.Unlock()
  462. }
  463. // Next advances the read pointer into the journal by one entry.
  464. func (j *Journal) Next() (uint64, error) {
  465. sd_journal_next, err := getFunction("sd_journal_next")
  466. if err != nil {
  467. return 0, err
  468. }
  469. j.mu.Lock()
  470. r := C.my_sd_journal_next(sd_journal_next, j.cjournal)
  471. j.mu.Unlock()
  472. if r < 0 {
  473. return 0, fmt.Errorf("failed to iterate journal: %d", syscall.Errno(-r))
  474. }
  475. return uint64(r), nil
  476. }
  477. // NextSkip advances the read pointer by multiple entries at once,
  478. // as specified by the skip parameter.
  479. func (j *Journal) NextSkip(skip uint64) (uint64, error) {
  480. sd_journal_next_skip, err := getFunction("sd_journal_next_skip")
  481. if err != nil {
  482. return 0, err
  483. }
  484. j.mu.Lock()
  485. r := C.my_sd_journal_next_skip(sd_journal_next_skip, j.cjournal, C.uint64_t(skip))
  486. j.mu.Unlock()
  487. if r < 0 {
  488. return 0, fmt.Errorf("failed to iterate journal: %d", syscall.Errno(-r))
  489. }
  490. return uint64(r), nil
  491. }
  492. // Previous sets the read pointer into the journal back by one entry.
  493. func (j *Journal) Previous() (uint64, error) {
  494. sd_journal_previous, err := getFunction("sd_journal_previous")
  495. if err != nil {
  496. return 0, err
  497. }
  498. j.mu.Lock()
  499. r := C.my_sd_journal_previous(sd_journal_previous, j.cjournal)
  500. j.mu.Unlock()
  501. if r < 0 {
  502. return 0, fmt.Errorf("failed to iterate journal: %d", syscall.Errno(-r))
  503. }
  504. return uint64(r), nil
  505. }
  506. // PreviousSkip sets back the read pointer by multiple entries at once,
  507. // as specified by the skip parameter.
  508. func (j *Journal) PreviousSkip(skip uint64) (uint64, error) {
  509. sd_journal_previous_skip, err := getFunction("sd_journal_previous_skip")
  510. if err != nil {
  511. return 0, err
  512. }
  513. j.mu.Lock()
  514. r := C.my_sd_journal_previous_skip(sd_journal_previous_skip, j.cjournal, C.uint64_t(skip))
  515. j.mu.Unlock()
  516. if r < 0 {
  517. return 0, fmt.Errorf("failed to iterate journal: %d", syscall.Errno(-r))
  518. }
  519. return uint64(r), nil
  520. }
  521. func (j *Journal) getData(field string) (unsafe.Pointer, C.int, error) {
  522. sd_journal_get_data, err := getFunction("sd_journal_get_data")
  523. if err != nil {
  524. return nil, 0, err
  525. }
  526. f := C.CString(field)
  527. defer C.free(unsafe.Pointer(f))
  528. var d unsafe.Pointer
  529. var l C.size_t
  530. j.mu.Lock()
  531. r := C.my_sd_journal_get_data(sd_journal_get_data, j.cjournal, f, &d, &l)
  532. j.mu.Unlock()
  533. if r < 0 {
  534. return nil, 0, fmt.Errorf("failed to read message: %d", syscall.Errno(-r))
  535. }
  536. return d, C.int(l), nil
  537. }
  538. // GetData gets the data object associated with a specific field from the
  539. // current journal entry.
  540. func (j *Journal) GetData(field string) (string, error) {
  541. d, l, err := j.getData(field)
  542. if err != nil {
  543. return "", err
  544. }
  545. return C.GoStringN((*C.char)(d), l), nil
  546. }
  547. // GetDataValue gets the data object associated with a specific field from the
  548. // current journal entry, returning only the value of the object.
  549. func (j *Journal) GetDataValue(field string) (string, error) {
  550. val, err := j.GetData(field)
  551. if err != nil {
  552. return "", err
  553. }
  554. return strings.SplitN(val, "=", 2)[1], nil
  555. }
  556. // GetDataBytes gets the data object associated with a specific field from the
  557. // current journal entry.
  558. func (j *Journal) GetDataBytes(field string) ([]byte, error) {
  559. d, l, err := j.getData(field)
  560. if err != nil {
  561. return nil, err
  562. }
  563. return C.GoBytes(d, l), nil
  564. }
  565. // GetDataValueBytes gets the data object associated with a specific field from the
  566. // current journal entry, returning only the value of the object.
  567. func (j *Journal) GetDataValueBytes(field string) ([]byte, error) {
  568. val, err := j.GetDataBytes(field)
  569. if err != nil {
  570. return nil, err
  571. }
  572. return bytes.SplitN(val, []byte("="), 2)[1], nil
  573. }
  574. // GetEntry returns a full representation of a journal entry with
  575. // all key-value pairs of data as well as address fields (cursor, realtime
  576. // timestamp and monotonic timestamp)
  577. func (j *Journal) GetEntry() (*JournalEntry, error) {
  578. sd_journal_get_realtime_usec, err := getFunction("sd_journal_get_realtime_usec")
  579. if err != nil {
  580. return nil, err
  581. }
  582. sd_journal_get_monotonic_usec, err := getFunction("sd_journal_get_monotonic_usec")
  583. if err != nil {
  584. return nil, err
  585. }
  586. sd_journal_get_cursor, err := getFunction("sd_journal_get_cursor")
  587. if err != nil {
  588. return nil, err
  589. }
  590. sd_journal_restart_data, err := getFunction("sd_journal_restart_data")
  591. if err != nil {
  592. return nil, err
  593. }
  594. sd_journal_enumerate_data, err := getFunction("sd_journal_enumerate_data")
  595. if err != nil {
  596. return nil, err
  597. }
  598. j.mu.Lock()
  599. defer j.mu.Unlock()
  600. var r C.int
  601. entry := &JournalEntry{Fields: make(map[string]string)}
  602. var realtimeUsec C.uint64_t
  603. r = C.my_sd_journal_get_realtime_usec(sd_journal_get_realtime_usec, j.cjournal, &realtimeUsec)
  604. if r < 0 {
  605. return nil, fmt.Errorf("failed to get realtime timestamp: %d", syscall.Errno(-r))
  606. }
  607. entry.RealtimeTimestamp = uint64(realtimeUsec)
  608. var monotonicUsec C.uint64_t
  609. var boot_id C.sd_id128_t
  610. r = C.my_sd_journal_get_monotonic_usec(sd_journal_get_monotonic_usec, j.cjournal, &monotonicUsec, &boot_id)
  611. if r < 0 {
  612. return nil, fmt.Errorf("failed to get monotonic timestamp: %d", syscall.Errno(-r))
  613. }
  614. entry.MonotonicTimestamp = uint64(monotonicUsec)
  615. var c *C.char
  616. // since the pointer is mutated by sd_journal_get_cursor, need to wait
  617. // until after the call to free the memory
  618. r = C.my_sd_journal_get_cursor(sd_journal_get_cursor, j.cjournal, &c)
  619. defer C.free(unsafe.Pointer(c))
  620. if r < 0 {
  621. return nil, fmt.Errorf("failed to get cursor: %d", syscall.Errno(-r))
  622. }
  623. entry.Cursor = C.GoString(c)
  624. // Implements the JOURNAL_FOREACH_DATA_RETVAL macro from journal-internal.h
  625. var d unsafe.Pointer
  626. var l C.size_t
  627. C.my_sd_journal_restart_data(sd_journal_restart_data, j.cjournal)
  628. for {
  629. r = C.my_sd_journal_enumerate_data(sd_journal_enumerate_data, j.cjournal, &d, &l)
  630. if r == 0 {
  631. break
  632. }
  633. if r < 0 {
  634. return nil, fmt.Errorf("failed to read message field: %d", syscall.Errno(-r))
  635. }
  636. msg := C.GoStringN((*C.char)(d), C.int(l))
  637. kv := strings.SplitN(msg, "=", 2)
  638. if len(kv) < 2 {
  639. return nil, fmt.Errorf("failed to parse field")
  640. }
  641. entry.Fields[kv[0]] = kv[1]
  642. }
  643. return entry, nil
  644. }
  645. // SetDataThresold sets the data field size threshold for data returned by
  646. // GetData. To retrieve the complete data fields this threshold should be
  647. // turned off by setting it to 0, so that the library always returns the
  648. // complete data objects.
  649. func (j *Journal) SetDataThreshold(threshold uint64) error {
  650. sd_journal_set_data_threshold, err := getFunction("sd_journal_set_data_threshold")
  651. if err != nil {
  652. return err
  653. }
  654. j.mu.Lock()
  655. r := C.my_sd_journal_set_data_threshold(sd_journal_set_data_threshold, j.cjournal, C.size_t(threshold))
  656. j.mu.Unlock()
  657. if r < 0 {
  658. return fmt.Errorf("failed to set data threshold: %d", syscall.Errno(-r))
  659. }
  660. return nil
  661. }
  662. // GetRealtimeUsec gets the realtime (wallclock) timestamp of the current
  663. // journal entry.
  664. func (j *Journal) GetRealtimeUsec() (uint64, error) {
  665. var usec C.uint64_t
  666. sd_journal_get_realtime_usec, err := getFunction("sd_journal_get_realtime_usec")
  667. if err != nil {
  668. return 0, err
  669. }
  670. j.mu.Lock()
  671. r := C.my_sd_journal_get_realtime_usec(sd_journal_get_realtime_usec, j.cjournal, &usec)
  672. j.mu.Unlock()
  673. if r < 0 {
  674. return 0, fmt.Errorf("failed to get realtime timestamp: %d", syscall.Errno(-r))
  675. }
  676. return uint64(usec), nil
  677. }
  678. // GetMonotonicUsec gets the monotonic timestamp of the current journal entry.
  679. func (j *Journal) GetMonotonicUsec() (uint64, error) {
  680. var usec C.uint64_t
  681. var boot_id C.sd_id128_t
  682. sd_journal_get_monotonic_usec, err := getFunction("sd_journal_get_monotonic_usec")
  683. if err != nil {
  684. return 0, err
  685. }
  686. j.mu.Lock()
  687. r := C.my_sd_journal_get_monotonic_usec(sd_journal_get_monotonic_usec, j.cjournal, &usec, &boot_id)
  688. j.mu.Unlock()
  689. if r < 0 {
  690. return 0, fmt.Errorf("failed to get monotonic timestamp: %d", syscall.Errno(-r))
  691. }
  692. return uint64(usec), nil
  693. }
  694. // GetCursor gets the cursor of the current journal entry.
  695. func (j *Journal) GetCursor() (string, error) {
  696. sd_journal_get_cursor, err := getFunction("sd_journal_get_cursor")
  697. if err != nil {
  698. return "", err
  699. }
  700. var d *C.char
  701. // since the pointer is mutated by sd_journal_get_cursor, need to wait
  702. // until after the call to free the memory
  703. j.mu.Lock()
  704. r := C.my_sd_journal_get_cursor(sd_journal_get_cursor, j.cjournal, &d)
  705. j.mu.Unlock()
  706. defer C.free(unsafe.Pointer(d))
  707. if r < 0 {
  708. return "", fmt.Errorf("failed to get cursor: %d", syscall.Errno(-r))
  709. }
  710. cursor := C.GoString(d)
  711. return cursor, nil
  712. }
  713. // TestCursor checks whether the current position in the journal matches the
  714. // specified cursor
  715. func (j *Journal) TestCursor(cursor string) error {
  716. sd_journal_test_cursor, err := getFunction("sd_journal_test_cursor")
  717. if err != nil {
  718. return err
  719. }
  720. c := C.CString(cursor)
  721. defer C.free(unsafe.Pointer(c))
  722. j.mu.Lock()
  723. r := C.my_sd_journal_test_cursor(sd_journal_test_cursor, j.cjournal, c)
  724. j.mu.Unlock()
  725. if r < 0 {
  726. return fmt.Errorf("failed to test to cursor %q: %d", cursor, syscall.Errno(-r))
  727. }
  728. return nil
  729. }
  730. // SeekHead seeks to the beginning of the journal, i.e. the oldest available
  731. // entry.
  732. func (j *Journal) SeekHead() error {
  733. sd_journal_seek_head, err := getFunction("sd_journal_seek_head")
  734. if err != nil {
  735. return err
  736. }
  737. j.mu.Lock()
  738. r := C.my_sd_journal_seek_head(sd_journal_seek_head, j.cjournal)
  739. j.mu.Unlock()
  740. if r < 0 {
  741. return fmt.Errorf("failed to seek to head of journal: %d", syscall.Errno(-r))
  742. }
  743. return nil
  744. }
  745. // SeekTail may be used to seek to the end of the journal, i.e. the most recent
  746. // available entry.
  747. func (j *Journal) SeekTail() error {
  748. sd_journal_seek_tail, err := getFunction("sd_journal_seek_tail")
  749. if err != nil {
  750. return err
  751. }
  752. j.mu.Lock()
  753. r := C.my_sd_journal_seek_tail(sd_journal_seek_tail, j.cjournal)
  754. j.mu.Unlock()
  755. if r < 0 {
  756. return fmt.Errorf("failed to seek to tail of journal: %d", syscall.Errno(-r))
  757. }
  758. return nil
  759. }
  760. // SeekRealtimeUsec seeks to the entry with the specified realtime (wallclock)
  761. // timestamp, i.e. CLOCK_REALTIME.
  762. func (j *Journal) SeekRealtimeUsec(usec uint64) error {
  763. sd_journal_seek_realtime_usec, err := getFunction("sd_journal_seek_realtime_usec")
  764. if err != nil {
  765. return err
  766. }
  767. j.mu.Lock()
  768. r := C.my_sd_journal_seek_realtime_usec(sd_journal_seek_realtime_usec, j.cjournal, C.uint64_t(usec))
  769. j.mu.Unlock()
  770. if r < 0 {
  771. return fmt.Errorf("failed to seek to %d: %d", usec, syscall.Errno(-r))
  772. }
  773. return nil
  774. }
  775. // SeekCursor seeks to a concrete journal cursor.
  776. func (j *Journal) SeekCursor(cursor string) error {
  777. sd_journal_seek_cursor, err := getFunction("sd_journal_seek_cursor")
  778. if err != nil {
  779. return err
  780. }
  781. c := C.CString(cursor)
  782. defer C.free(unsafe.Pointer(c))
  783. j.mu.Lock()
  784. r := C.my_sd_journal_seek_cursor(sd_journal_seek_cursor, j.cjournal, c)
  785. j.mu.Unlock()
  786. if r < 0 {
  787. return fmt.Errorf("failed to seek to cursor %q: %d", cursor, syscall.Errno(-r))
  788. }
  789. return nil
  790. }
  791. // Wait will synchronously wait until the journal gets changed. The maximum time
  792. // this call sleeps may be controlled with the timeout parameter. If
  793. // sdjournal.IndefiniteWait is passed as the timeout parameter, Wait will
  794. // wait indefinitely for a journal change.
  795. func (j *Journal) Wait(timeout time.Duration) int {
  796. var to uint64
  797. sd_journal_wait, err := getFunction("sd_journal_wait")
  798. if err != nil {
  799. return -1
  800. }
  801. if timeout == IndefiniteWait {
  802. // sd_journal_wait(3) calls for a (uint64_t) -1 to be passed to signify
  803. // indefinite wait, but using a -1 overflows our C.uint64_t, so we use an
  804. // equivalent hex value.
  805. to = 0xffffffffffffffff
  806. } else {
  807. to = uint64(time.Now().Add(timeout).Unix() / 1000)
  808. }
  809. j.mu.Lock()
  810. r := C.my_sd_journal_wait(sd_journal_wait, j.cjournal, C.uint64_t(to))
  811. j.mu.Unlock()
  812. return int(r)
  813. }
  814. // GetUsage returns the journal disk space usage, in bytes.
  815. func (j *Journal) GetUsage() (uint64, error) {
  816. var out C.uint64_t
  817. sd_journal_get_usage, err := getFunction("sd_journal_get_usage")
  818. if err != nil {
  819. return 0, err
  820. }
  821. j.mu.Lock()
  822. r := C.my_sd_journal_get_usage(sd_journal_get_usage, j.cjournal, &out)
  823. j.mu.Unlock()
  824. if r < 0 {
  825. return 0, fmt.Errorf("failed to get journal disk space usage: %d", syscall.Errno(-r))
  826. }
  827. return uint64(out), nil
  828. }
  829. // GetUniqueValues returns all unique values for a given field.
  830. func (j *Journal) GetUniqueValues(field string) ([]string, error) {
  831. var result []string
  832. sd_journal_query_unique, err := getFunction("sd_journal_query_unique")
  833. if err != nil {
  834. return nil, err
  835. }
  836. sd_journal_enumerate_unique, err := getFunction("sd_journal_enumerate_unique")
  837. if err != nil {
  838. return nil, err
  839. }
  840. sd_journal_restart_unique, err := getFunction("sd_journal_restart_unique")
  841. if err != nil {
  842. return nil, err
  843. }
  844. j.mu.Lock()
  845. defer j.mu.Unlock()
  846. f := C.CString(field)
  847. defer C.free(unsafe.Pointer(f))
  848. r := C.my_sd_journal_query_unique(sd_journal_query_unique, j.cjournal, f)
  849. if r < 0 {
  850. return nil, fmt.Errorf("failed to query journal: %d", syscall.Errno(-r))
  851. }
  852. // Implements the SD_JOURNAL_FOREACH_UNIQUE macro from sd-journal.h
  853. var d unsafe.Pointer
  854. var l C.size_t
  855. C.my_sd_journal_restart_unique(sd_journal_restart_unique, j.cjournal)
  856. for {
  857. r = C.my_sd_journal_enumerate_unique(sd_journal_enumerate_unique, j.cjournal, &d, &l)
  858. if r == 0 {
  859. break
  860. }
  861. if r < 0 {
  862. return nil, fmt.Errorf("failed to read message field: %d", syscall.Errno(-r))
  863. }
  864. msg := C.GoStringN((*C.char)(d), C.int(l))
  865. kv := strings.SplitN(msg, "=", 2)
  866. if len(kv) < 2 {
  867. return nil, fmt.Errorf("failed to parse field")
  868. }
  869. result = append(result, kv[1])
  870. }
  871. return result, nil
  872. }