int main(int argc, char *argv[]) { int r; sd_journal *j; r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY); if (r < 0) { fprintf(stderr, "Failed to open journal: %s\n", strerror(-r)); return 1; } for (;;) { const void *d; size_t l; r = sd_journal_next(j); if (r < 0) { fprintf(stderr, "Failed to iterate to next entry: %s\n", strerror(-r)); break; } if (r == 0) { /* Reached the end, let's wait for changes, and try again */ r = sd_journal_wait(j, (uint64_t) -1); if (r < 0) { fprintf(stderr, "Failed to wait for changes: %s\n", strerror(-r)); break; } continue; } r = sd_journal_get_data(j, "MESSAGE", &d, &l); if (r < 0) { fprintf(stderr, "Failed to read message field: %s\n", strerror(-r)); continue; } printf("%.*s\n", (int) l, (const char*) d); } sd_journal_close(j); return 0; }
int main(int argc, char *argv[]) { unsigned n = 0; _cleanup_journal_close_ sd_journal*j = NULL; log_set_max_level(LOG_DEBUG); assert_se(sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY) >= 0); assert_se(sd_journal_add_match(j, "_TRANSPORT=syslog", 0) >= 0); assert_se(sd_journal_add_match(j, "_UID=0", 0) >= 0); SD_JOURNAL_FOREACH_BACKWARDS(j) { const void *d; size_t l; assert_se(sd_journal_get_data(j, "MESSAGE", &d, &l) >= 0); printf("%.*s\n", (int) l, (char*) d); n ++; if (n >= 10) break; } return 0; }
static void verify_contents(sd_journal *j, unsigned skip) { unsigned i; assert(j); i = 0; SD_JOURNAL_FOREACH(j) { const void *d; char *k, *c; size_t l; unsigned u; assert_se(sd_journal_get_cursor(j, &k) >= 0); printf("cursor: %s\n", k); free(k); assert_se(sd_journal_get_data(j, "MAGIC", &d, &l) >= 0); printf("\t%.*s\n", (int) l, (const char*) d); assert_se(sd_journal_get_data(j, "NUMBER", &d, &l) >= 0); assert_se(k = strndup(d, l)); printf("\t%s\n", k); if (skip > 0) { assert_se(safe_atou(k + 7, &u) >= 0); assert_se(i == u); i += skip; } free(k); assert_se(sd_journal_get_cursor(j, &c) >= 0); assert_se(sd_journal_test_cursor(j, c) > 0); free(c); } if (skip > 0) assert_se(i == N_ENTRIES); }
static void test_check_number (sd_journal *j, int n) { const void *d; _cleanup_free_ char *k; size_t l; int x; assert_ret(sd_journal_get_data(j, "NUMBER", &d, &l)); assert_se(k = strndup(d, l)); printf("%s\n", k); assert_se(safe_atoi(k + 7, &x) >= 0); assert_se(n == x); }
/* Return a strndup (or NULL) of a field of the current journal entry, since sd_journal_get_data returns data that is not \0-terminated. */ char * my_sd_journal_get_data(sd_journal *j, const char *field) { int rc; const char* str; size_t str_len; assert (j != NULL); assert (field != NULL); rc = sd_journal_get_data(j, field, (const void**) & str, & str_len); if (rc < 0) return NULL; return strndup (str, str_len); }
static int journal_get_data (lua_State *L) { sd_journal *j = check_journal(L, 1); const char *field = luaL_checkstring(L, 2); const void *data; size_t length; int err = sd_journal_get_data(j, field, &data, &length); if (err == -ENOENT) { lua_pushboolean(L, 0); lua_pushnil(L); return 2; } else if (err != 0) { return handle_error(L, -err); } else { lua_pushboolean(L, 1); lua_pushlstring(L, data, length); return 2; } }
int main(int argc, char *argv[]) { JournalFile *one, *two, *three; char t[] = "/tmp/journal-stream-XXXXXX"; unsigned i; _cleanup_journal_close_ sd_journal *j = NULL; char *z; const void *data; size_t l; log_set_max_level(LOG_DEBUG); assert_se(mkdtemp(t)); assert_se(chdir(t) >= 0); assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0666, true, NULL, NULL, NULL, &one) == 0); assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0666, true, NULL, NULL, NULL, &two) == 0); assert_se(journal_file_open("three.journal", O_RDWR|O_CREAT, 0666, true, NULL, NULL, NULL, &three) == 0); for (i = 0; i < N_ENTRIES; i++) { char *p, *q; dual_timestamp ts; struct iovec iovec[2]; dual_timestamp_get(&ts); assert_se(asprintf(&p, "NUMBER=%u", i) >= 0); iovec[0].iov_base = p; iovec[0].iov_len = strlen(p); assert_se(asprintf(&q, "MAGIC=%s", i % 5 == 0 ? "quux" : "waldo") >= 0); iovec[1].iov_base = q; iovec[1].iov_len = strlen(q); if (i % 10 == 0) assert_se(journal_file_append_entry(three, &ts, iovec, 2, NULL, NULL, NULL) == 0); else { if (i % 3 == 0) assert_se(journal_file_append_entry(two, &ts, iovec, 2, NULL, NULL, NULL) == 0); assert_se(journal_file_append_entry(one, &ts, iovec, 2, NULL, NULL, NULL) == 0); } free(p); free(q); } journal_file_close(one); journal_file_close(two); journal_file_close(three); assert_se(sd_journal_open_directory(&j, t, 0) >= 0); assert_se(sd_journal_add_match(j, "MAGIC=quux", 0) >= 0); SD_JOURNAL_FOREACH_BACKWARDS(j) { _cleanup_free_ char *c = NULL; assert_se(sd_journal_get_data(j, "NUMBER", &data, &l) >= 0); printf("\t%.*s\n", (int) l, (const char*) data); assert_se(sd_journal_get_cursor(j, &c) >= 0); assert_se(sd_journal_test_cursor(j, c) > 0); } SD_JOURNAL_FOREACH(j) { _cleanup_free_ char *c = NULL; assert_se(sd_journal_get_data(j, "NUMBER", &data, &l) >= 0); printf("\t%.*s\n", (int) l, (const char*) data); assert_se(sd_journal_get_cursor(j, &c) >= 0); assert_se(sd_journal_test_cursor(j, c) > 0); } sd_journal_flush_matches(j); verify_contents(j, 1); printf("NEXT TEST\n"); assert_se(sd_journal_add_match(j, "MAGIC=quux", 0) >= 0); assert_se(z = journal_make_match_string(j)); printf("resulting match expression is: %s\n", z); free(z); verify_contents(j, 5); printf("NEXT TEST\n"); sd_journal_flush_matches(j); assert_se(sd_journal_add_match(j, "MAGIC=waldo", 0) >= 0); assert_se(sd_journal_add_match(j, "NUMBER=10", 0) >= 0); assert_se(sd_journal_add_match(j, "NUMBER=11", 0) >= 0); assert_se(sd_journal_add_match(j, "NUMBER=12", 0) >= 0); assert_se(z = journal_make_match_string(j)); printf("resulting match expression is: %s\n", z); free(z); verify_contents(j, 0); assert_se(sd_journal_query_unique(j, "NUMBER") >= 0); SD_JOURNAL_FOREACH_UNIQUE(j, data, l) printf("%.*s\n", (int) l, (const char*) data); assert_se(rm_rf_dangerous(t, false, true, false) >= 0); return 0; }
char *get_entry_string(){ const void *data; json_t *message = json_object(); size_t length; // journal meta information, prefixed by '__' char *cursor; uint64_t realtime_usec; uint64_t monotonic_usec; sd_id128_t boot_id; /* mapping from systemd- to GELF- field names */ const char *fn_sd_host="_HOSTNAME", *fn_gelf_host="host"; const char *fn_sd_msg="MESSAGE", *fn_gelf_msg="short_message"; const char /**fn_sd_time="__REALTIME_TIMESTAMP",*/ *fn_gelf_time="timestamp"; const char *fn_sd_prio="PRIORITY", *fn_gelf_prio="level"; int rc = 0; //add version field necessary for GELF json_object_set_new(message, "version", json_string("1.1")); /* get data necessary for GELF*/ rc = sd_journal_get_data(j, fn_sd_host, &data, &length); if (!rc){ char *v = get_value(data, length); assert(v); json_object_set_new(message, fn_gelf_host, json_string(v)); free(v); } else{ json_object_set_new(message, fn_gelf_host, json_string("not_available")); } rc = sd_journal_get_data(j, fn_sd_msg, &data, &length); if (!rc){ char *v = get_value(data, length); assert(v); json_object_set_new(message, fn_gelf_msg, json_string(v)); free(v); } else{ json_object_set_new(message, fn_gelf_msg, json_string("not_available")); } rc = sd_journal_get_data(j, fn_sd_prio, &data, &length); if (!rc){ char *v = get_value(data, length); assert(v); int prio = strtol(v, NULL, 10); if (prio<0) prio = 0; if (prio>7) prio = 7; //TODO: log meldung absetzen json_object_set_new(message, fn_gelf_prio, json_integer(prio)); free(v); } else{ json_object_set_new(message, fn_gelf_prio, json_string("not_available")); } // get systemd journal meta fields cursor, realtime- and monotonic timestamp // __REALTIME_TIMESTAMP corresponds to GELF necessary timestamp const char *meta_prefixes[] = {"___CURSOR", fn_gelf_time , "___MONOTONIC_TIMESTAMP" }; sd_journal_get_cursor( j, &cursor ); // needs to be free'd afterwards json_object_set_new(message, meta_prefixes[0], json_string(cursor)); free(cursor); sd_journal_get_realtime_usec( j, &realtime_usec ); json_object_set_new(message, meta_prefixes[1], json_integer(realtime_usec)); sd_journal_get_monotonic_usec( j, &monotonic_usec, &boot_id); json_object_set_new(message, meta_prefixes[2], json_integer(monotonic_usec)); /* get all remaining fields */ // (PRIORITY, _HOSTNAME, and MESSAGE are read again) // format of prefixes: additional '_' for additional fields in GELF // format of retrieved arguments: data="FIELD_NAME=field_value" length= SD_JOURNAL_FOREACH_DATA(j, data, length){ char *v = get_value(data, length); assert(v); char *k = get_key(data); assert(k); json_object_set_new(message, k, json_string(v)); free(v); free(k); }
/* Read journal log while data are available, each read() reads one * record of printk buffer. */ static rsRetVal readjournal() { DEFiRet; struct timeval tv; uint64_t timestamp; struct json_object *json = NULL; int r; /* Information from messages */ char *message; char *sys_pid; char *sys_iden; char *sys_iden_help; const void *get; const void *pidget; char *parse; size_t length; size_t pidlength; const void *equal_sign; struct json_object *jval; char *data; char *name; size_t l; long prefixlen = 0; int severity = cs.iDfltSeverity; int facility = cs.iDfltFacility; /* Get message text */ if (sd_journal_get_data(j, "MESSAGE", &get, &length) < 0) { message = strdup(""); } else { message = strndup(((const char*)get)+8, length-8); if (message == NULL) { iRet = RS_RET_OUT_OF_MEMORY; goto ret; } } /* Get message severity ("priority" in journald's terminology) */ if (sd_journal_get_data(j, "PRIORITY", &get, &length) >= 0) { if (length == 10) { severity = ((char *)get)[9] - '0'; if (severity < 0 || 7 < severity) { dbgprintf("The value of the 'PRIORITY' field is " "out of bounds: %d, resetting\n", severity); severity = cs.iDfltSeverity; } } else { dbgprintf("The value of the 'PRIORITY' field has an " "unexpected length: %d\n", length); } } /* Get syslog facility */ if (sd_journal_get_data(j, "SYSLOG_FACILITY", &get, &length) >= 0) { if (length == 17 || length == 18) { facility = ((char *)get)[16] - '0'; if (length == 18) { facility *= 10; facility += ((char *)get)[17] - '0'; } if (facility < 0 || 23 < facility) { dbgprintf("The value of the 'FACILITY' field is " "out of bounds: %d, resetting\n", facility); facility = cs.iDfltFacility; } } else { dbgprintf("The value of the 'FACILITY' field has an " "unexpected length: %d\n", length); } } /* Get message identifier, client pid and add ':' */ if (sd_journal_get_data(j, "SYSLOG_IDENTIFIER", &get, &length) >= 0) { sys_iden = strndup(((const char*)get)+18, length-18); } else { sys_iden = strdup("journal"); } if (sys_iden == NULL) { iRet = RS_RET_OUT_OF_MEMORY; goto free_message; } if (sd_journal_get_data(j, "SYSLOG_PID", &pidget, &pidlength) >= 0) { sys_pid = strndup(((const char*)pidget)+11, pidlength-11); if (sys_pid == NULL) { iRet = RS_RET_OUT_OF_MEMORY; free (sys_iden); goto free_message; } } else { sys_pid = NULL; } if (sys_pid) { r = asprintf(&sys_iden_help, "%s[%s]:", sys_iden, sys_pid); } else { r = asprintf(&sys_iden_help, "%s:", sys_iden); } free (sys_iden); free (sys_pid); if (-1 == r) { iRet = RS_RET_OUT_OF_MEMORY; goto finalize_it; } json = json_object_new_object(); SD_JOURNAL_FOREACH_DATA(j, get, l) { /* locate equal sign, this is always present */ equal_sign = memchr(get, '=', l); /* ... but we know better than to trust the specs */ if (equal_sign == NULL) { errmsg.LogError(0, RS_RET_ERR, "SD_JOURNAL_FOREACH_DATA()" "returned a malformed field (has no '='): '%s'", (char*)get); continue; /* skip the entry */ } /* get length of journal data prefix */ prefixlen = ((char *)equal_sign - (char *)get); /* translate name fields to lumberjack names */ parse = (char *)get; switch (*parse) { case '_': ++parse; if (*parse == 'P') { if (!strncmp(parse+1, "ID=", 4)) { name = strdup("pid"); } else { name = strndup(get, prefixlen); } } else if (*parse == 'G') { if (!strncmp(parse+1, "ID=", 4)) { name = strdup("gid"); } else { name = strndup(get, prefixlen); } } else if (*parse == 'U') { if (!strncmp(parse+1, "ID=", 4)) { name = strdup("uid"); } else { name = strndup(get, prefixlen); } } else if (*parse == 'E') { if (!strncmp(parse+1, "XE=", 4)) { name = strdup("exe"); } else { name = strndup(get, prefixlen); } } else if (*parse == 'C') { parse++; if (*parse == 'O') { if (!strncmp(parse+1, "MM=", 4)) { name = strdup("appname"); } else { name = strndup(get, prefixlen); } } else if (*parse == 'M') { if (!strncmp(parse+1, "DLINE=", 7)) { name = strdup("cmd"); } else { name = strndup(get, prefixlen); } } else { name = strndup(get, prefixlen); } } else { name = strndup(get, prefixlen); } break; default: name = strndup(get, prefixlen); break; } if (name == NULL) { iRet = RS_RET_OUT_OF_MEMORY; goto ret; } prefixlen++; /* remove '=' */ data = strndup(((const char*)get) + prefixlen, l - prefixlen); if (data == NULL) { iRet = RS_RET_OUT_OF_MEMORY; free (name); goto ret; } /* and save them to json object */ jval = json_object_new_string((char *)data); json_object_object_add(json, name, jval); free (data); free (name); }
tlog_grc tlog_journal_json_reader_read(struct tlog_json_reader *reader, struct json_object **pobject) { struct tlog_journal_json_reader *journal_json_reader = (struct tlog_journal_json_reader*)reader; tlog_grc grc; int sd_rc; struct json_object *object = NULL; /* If we ran out of time limit */ if (journal_json_reader->last > journal_json_reader->until) { goto exit; } /* Advance to the next entry */ sd_rc = sd_journal_next(journal_json_reader->journal); /* If failed */ if (sd_rc < 0) { grc = TLOG_GRC_FROM(systemd, sd_rc); goto cleanup; /* If got an entry */ } else if (sd_rc > 0) { const char *field_ptr; size_t field_len; const char *message_ptr; size_t message_len; /* Advance entry counter */ journal_json_reader->entry++; /* Get the entry realtime timestamp */ sd_rc = sd_journal_get_realtime_usec(journal_json_reader->journal, &journal_json_reader->last); if (sd_rc < 0) { grc = TLOG_GRC_FROM(systemd, sd_rc); goto cleanup; } if (journal_json_reader->last > journal_json_reader->until) { goto exit; } /* Get the entry message field data */ sd_rc = sd_journal_get_data(journal_json_reader->journal, "MESSAGE", (const void **)&field_ptr, &field_len); if (sd_rc < 0) { grc = TLOG_GRC_FROM(systemd, sd_rc); goto cleanup; } /* Extract the message */ message_ptr = (const char *)memchr(field_ptr, '=', field_len); if (message_ptr == NULL) { grc = TLOG_RC_FAILURE; goto cleanup; } message_ptr++; message_len = field_len - (message_ptr - field_ptr); /* Parse the message */ object = json_tokener_parse_ex(journal_json_reader->tok, message_ptr, message_len); if (object == NULL) { grc = TLOG_GRC_FROM( json, json_tokener_get_error(journal_json_reader->tok)); goto cleanup; } } exit: *pobject = object; object = NULL; grc = TLOG_RC_OK; cleanup: json_object_put(object); return grc; }
/* Read journal log while data are available, each read() reads one * record of printk buffer. */ static rsRetVal readjournal() { DEFiRet; struct timeval tv; uint64_t timestamp; struct json_object *json = NULL; int r; /* Information from messages */ char *message; char *sys_pid; char *sys_iden; char *sys_iden_help; const void *get; const void *pidget; char *parse; char *get2; size_t length; size_t pidlength; const void *equal_sign; struct json_object *jval; char *data; char *name; size_t l; long prefixlen = 0; int priority = 0; int facility = 0; /* Get message text */ if (sd_journal_get_data(j, "MESSAGE", &get, &length) < 0) { logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar *)"log message from journal doesn't have MESSAGE", 0); iRet = RS_RET_OK; goto ret; } message = strndup(get+8, length-8); if (message == NULL) { iRet = RS_RET_OUT_OF_MEMORY; goto ret; } /* Get message priority */ if (sd_journal_get_data(j, "PRIORITY", &get, &length) >= 0) { get2 = strndup(get, length); priority = ((char *)get2)[9] - '0'; free (get2); } /* Get syslog facility */ if (sd_journal_get_data(j, "SYSLOG_FACILITY", &get, &length) >= 0) { get2 = strndup(get, length); char f = ((char *)get2)[16]; if (f >= '0' && f <= '9') { facility += f - '0'; } f = ((char *)get2)[17]; if (f >= '0' && f <= '9') { facility *= 10; facility += (f - '0'); } free (get2); } else { /* message is missing facility -> internal systemd journal msg, drop */ iRet = RS_RET_OK; goto free_message; } /* Get message identifier, client pid and add ':' */ if (sd_journal_get_data(j, "SYSLOG_IDENTIFIER", &get, &length) >= 0) { sys_iden = strndup(get+18, length-18); } else { sys_iden = strdup("journal"); } if (sys_iden == NULL) { iRet = RS_RET_OUT_OF_MEMORY; goto free_message; } if (sd_journal_get_data(j, "SYSLOG_PID", &pidget, &pidlength) >= 0) { sys_pid = strndup(pidget+11, pidlength-11); if (sys_pid == NULL) { iRet = RS_RET_OUT_OF_MEMORY; free (sys_iden); goto free_message; } } else { sys_pid = NULL; } if (sys_pid) { r = asprintf(&sys_iden_help, "%s[%s]:", sys_iden, sys_pid); } else { r = asprintf(&sys_iden_help, "%s:", sys_iden); } free (sys_iden); free (sys_pid); if (-1 == r) { iRet = RS_RET_OUT_OF_MEMORY; goto finalize_it; } json = json_object_new_object(); SD_JOURNAL_FOREACH_DATA(j, get, l) { /* locate equal sign, this is always present */ equal_sign = memchr(get, '=', l); /* ... but we know better than to trust the specs */ if (equal_sign == NULL) { errmsg.LogError(0, RS_RET_ERR, "SD_JOURNAL_FOREACH_DATA()" "returned a malformed field (has no '='): '%s'", get); continue; /* skip the entry */ } /* get length of journal data prefix */ prefixlen = ((char *)equal_sign - (char *)get); /* translate name fields to lumberjack names */ parse = (char *)get; switch (*parse) { case '_': ++parse; if (*parse == 'P') { if (!strncmp(parse+1, "ID=", 4)) { name = strdup("pid"); } else { name = strndup(get, prefixlen); } } else if (*parse == 'G') { if (!strncmp(parse+1, "ID=", 4)) { name = strdup("gid"); } else { name = strndup(get, prefixlen); } } else if (*parse == 'U') { if (!strncmp(parse+1, "ID=", 4)) { name = strdup("uid"); } else { name = strndup(get, prefixlen); } } else if (*parse == 'E') { if (!strncmp(parse+1, "XE=", 4)) { name = strdup("exe"); } else { name = strndup(get, prefixlen); } } else if (*parse == 'C') { parse++; if (*parse == 'O') { if (!strncmp(parse+1, "MM=", 4)) { name = strdup("appname"); } else { name = strndup(get, prefixlen); } } else if (*parse == 'M') { if (!strncmp(parse+1, "DLINE=", 7)) { name = strdup("cmd"); } else { name = strndup(get, prefixlen); } } else { name = strndup(get, prefixlen); } } else { name = strndup(get, prefixlen); } break; default: name = strndup(get, prefixlen); break; } if (name == NULL) { iRet = RS_RET_OUT_OF_MEMORY; goto ret; } prefixlen++; /* remove '=' */ data = strndup(get + prefixlen, l - prefixlen); if (data == NULL) { iRet = RS_RET_OUT_OF_MEMORY; free (name); goto ret; } /* and save them to json object */ jval = json_object_new_string((char *)data); json_object_object_add(json, name, jval); free (data); free (name); }
QStringList UnitModel::getLastJrnlEntries(QString unit) const { QString match1, match2; int r, jflags; QStringList reply; const void *data; size_t length; uint64_t time; sd_journal *journal; if (!userBus.isEmpty()) { match1 = QString("USER_UNIT=" + unit); jflags = (SD_JOURNAL_LOCAL_ONLY | SD_JOURNAL_CURRENT_USER); } else { match1 = QString("_SYSTEMD_UNIT=" + unit); match2 = QString("UNIT=" + unit); jflags = (SD_JOURNAL_LOCAL_ONLY | SD_JOURNAL_SYSTEM); } r = sd_journal_open(&journal, jflags); if (r != 0) { qDebug() << "Failed to open journal"; return reply; } sd_journal_flush_matches(journal); r = sd_journal_add_match(journal, match1.toUtf8(), 0); if (r != 0) return reply; if (!match2.isEmpty()) { sd_journal_add_disjunction(journal); r = sd_journal_add_match(journal, match2.toUtf8(), 0); if (r != 0) return reply; } r = sd_journal_seek_tail(journal); if (r != 0) return reply; // Fetch the last 5 entries for (int i = 0; i < 5; ++i) { r = sd_journal_previous(journal); if (r == 1) { QString line; // Get the date and time r = sd_journal_get_realtime_usec(journal, &time); if (r == 0) { QDateTime date; date.setMSecsSinceEpoch(time/1000); line.append(date.toString("yyyy.MM.dd hh:mm")); } // Color messages according to priority r = sd_journal_get_data(journal, "PRIORITY", &data, &length); if (r == 0) { int prio = QString::fromUtf8((const char *)data, length).section('=',1).toInt(); if (prio <= 3) line.append("<span style='color:tomato;'>"); else if (prio == 4) line.append("<span style='color:khaki;'>"); else line.append("<span style='color:palegreen;'>"); } // Get the message itself r = sd_journal_get_data(journal, "MESSAGE", &data, &length); if (r == 0) { line.append(": " + QString::fromUtf8((const char *)data, length).section('=',1) + "</span>"); if (line.length() > 195) line = QString(line.left(195) + "..." + "</span>"); reply << line; } } else // previous failed, no more entries return reply; } sd_journal_close(journal); return reply; }