static int journal_get_monotonic_usec (lua_State *L) { sd_journal *j = check_journal(L, 1); uint64_t usec; sd_id128_t *boot_id = lua_newuserdata(L, sizeof(sd_id128_t)); int err = sd_journal_get_monotonic_usec(j, &usec, boot_id); if (err != 0) return handle_error(L, -err); lua_pushuint64(L, usec); lua_insert(L, 2); /* put below boot_id */ luaL_setmetatable(L, ID128_METATABLE); return 2; }
static int output_timestamp_monotonic(FILE *f, sd_journal *j, const char *monotonic) { sd_id128_t boot_id; uint64_t t; int r; assert(f); assert(j); r = -ENXIO; if (monotonic) r = safe_atou64(monotonic, &t); if (r < 0) r = sd_journal_get_monotonic_usec(j, &t, &boot_id); if (r < 0) return log_error_errno(r, "Failed to get monotonic timestamp: %m"); fprintf(f, "[%5"PRI_USEC".%06"PRI_USEC"]", t / USEC_PER_SEC, t % USEC_PER_SEC); return 1 + 5 + 1 + 6 + 1; }
/** * Write up to size bytes to buf. Return negative on error, and number of * bytes written otherwise. The last case is a kind of an error too. */ static ssize_t write_entry(char *buf, size_t size, Uploader *u) { int r; size_t pos = 0; assert(size <= SSIZE_MAX); while (true) { switch(u->entry_state) { case ENTRY_CURSOR: { free(u->current_cursor); u->current_cursor = NULL; r = sd_journal_get_cursor(u->journal, &u->current_cursor); if (r < 0) return log_error_errno(r, "Failed to get cursor: %m"); r = snprintf(buf + pos, size - pos, "__CURSOR=%s\n", u->current_cursor); if (pos + r > size) /* not enough space */ return pos; u->entry_state ++; if (pos + r == size) { /* exactly one character short, but we don't need it */ buf[size - 1] = '\n'; return size; } pos += r; } /* fall through */ case ENTRY_REALTIME: { usec_t realtime; r = sd_journal_get_realtime_usec(u->journal, &realtime); if (r < 0) return log_error_errno(r, "Failed to get realtime timestamp: %m"); r = snprintf(buf + pos, size - pos, "__REALTIME_TIMESTAMP="USEC_FMT"\n", realtime); if (r + pos > size) /* not enough space */ return pos; u->entry_state ++; if (r + pos == size) { /* exactly one character short, but we don't need it */ buf[size - 1] = '\n'; return size; } pos += r; } /* fall through */ case ENTRY_MONOTONIC: { usec_t monotonic; sd_id128_t boot_id; r = sd_journal_get_monotonic_usec(u->journal, &monotonic, &boot_id); if (r < 0) return log_error_errno(r, "Failed to get monotonic timestamp: %m"); r = snprintf(buf + pos, size - pos, "__MONOTONIC_TIMESTAMP="USEC_FMT"\n", monotonic); if (r + pos > size) /* not enough space */ return pos; u->entry_state ++; if (r + pos == size) { /* exactly one character short, but we don't need it */ buf[size - 1] = '\n'; return size; } pos += r; } /* fall through */ case ENTRY_BOOT_ID: { sd_id128_t boot_id; char sid[33]; r = sd_journal_get_monotonic_usec(u->journal, NULL, &boot_id); if (r < 0) return log_error_errno(r, "Failed to get monotonic timestamp: %m"); r = snprintf(buf + pos, size - pos, "_BOOT_ID=%s\n", sd_id128_to_string(boot_id, sid)); if (r + pos > size) /* not enough space */ return pos; u->entry_state ++; if (r + pos == size) { /* exactly one character short, but we don't need it */ buf[size - 1] = '\n'; return size; } pos += r; } /* fall through */ case ENTRY_NEW_FIELD: { u->field_pos = 0; r = sd_journal_enumerate_data(u->journal, &u->field_data, &u->field_length); if (r < 0) return log_error_errno(r, "Failed to move to next field in entry: %m"); else if (r == 0) { u->entry_state = ENTRY_OUTRO; continue; } if (!utf8_is_printable_newline(u->field_data, u->field_length, false)) { u->entry_state = ENTRY_BINARY_FIELD_START; continue; } u->entry_state ++; } /* fall through */ case ENTRY_TEXT_FIELD: case ENTRY_BINARY_FIELD: { bool done; size_t tocopy; done = size - pos > u->field_length - u->field_pos; if (done) tocopy = u->field_length - u->field_pos; else tocopy = size - pos; memcpy(buf + pos, (char*) u->field_data + u->field_pos, tocopy); if (done) { buf[pos + tocopy] = '\n'; pos += tocopy + 1; u->entry_state = ENTRY_NEW_FIELD; continue; } else { u->field_pos += tocopy; return size; } } case ENTRY_BINARY_FIELD_START: { const char *c; size_t len; c = memchr(u->field_data, '=', u->field_length); if (!c || c == u->field_data) { log_error("Invalid field."); return -EINVAL; } len = c - (const char*)u->field_data; /* need space for label + '\n' */ if (size - pos < len + 1) return pos; memcpy(buf + pos, u->field_data, len); buf[pos + len] = '\n'; pos += len + 1; u->field_pos = len + 1; u->entry_state ++; } /* fall through */ case ENTRY_BINARY_FIELD_SIZE: { uint64_t le64; /* need space for uint64_t */ if (size - pos < 8) return pos; le64 = htole64(u->field_length - u->field_pos); memcpy(buf + pos, &le64, 8); pos += 8; u->entry_state ++; continue; } case ENTRY_OUTRO: /* need space for '\n' */ if (size - pos < 1) return pos; buf[pos++] = '\n'; u->entry_state ++; u->entries_sent ++; return pos; default: assert_not_reached("WTF?"); } } assert_not_reached("WTF?"); }
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); }
int main(int argc, char *argv[]) { int r; sd_journal *j = NULL; unsigned line = 0; bool need_seek = false; sd_id128_t previous_boot_id; bool previous_boot_id_valid = false; bool have_pager; log_parse_environment(); log_open(); r = parse_argv(argc, argv); if (r <= 0) goto finish; if (arg_new_id128) { r = generate_new_id128(); goto finish; } #ifdef HAVE_ACL if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0) log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this message off."); #endif if (arg_directory) r = sd_journal_open_directory(&j, arg_directory, 0); else r = sd_journal_open(&j, arg_local ? SD_JOURNAL_LOCAL_ONLY : 0); if (r < 0) { log_error("Failed to open journal: %s", strerror(-r)); goto finish; } if (arg_print_header) { journal_print_header(j); r = 0; goto finish; } r = add_this_boot(j); if (r < 0) goto finish; r = add_matches(j, argv + optind); if (r < 0) goto finish; if (!arg_quiet) { usec_t start, end; char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX]; r = sd_journal_get_cutoff_realtime_usec(j, &start, &end); if (r < 0) { log_error("Failed to get cutoff: %s", strerror(-r)); goto finish; } if (r > 0) { if (arg_follow) printf("Logs begin at %s.\n", format_timestamp(start_buf, sizeof(start_buf), start)); else printf("Logs begin at %s, end at %s.\n", format_timestamp(start_buf, sizeof(start_buf), start), format_timestamp(end_buf, sizeof(end_buf), end)); } } if (arg_lines >= 0) { r = sd_journal_seek_tail(j); if (r < 0) { log_error("Failed to seek to tail: %s", strerror(-r)); goto finish; } r = sd_journal_previous_skip(j, arg_lines); } else { r = sd_journal_seek_head(j); if (r < 0) { log_error("Failed to seek to head: %s", strerror(-r)); goto finish; } r = sd_journal_next(j); } if (r < 0) { log_error("Failed to iterate through journal: %s", strerror(-r)); goto finish; } have_pager = !arg_no_pager && !arg_follow; if (have_pager) { columns(); pager_open(); } if (arg_output == OUTPUT_JSON) { fputc('[', stdout); fflush(stdout); } for (;;) { for (;;) { sd_id128_t boot_id; int flags = (arg_show_all*OUTPUT_SHOW_ALL | have_pager*OUTPUT_FULL_WIDTH); if (need_seek) { r = sd_journal_next(j); if (r < 0) { log_error("Failed to iterate through journal: %s", strerror(-r)); goto finish; } } if (r == 0) break; r = sd_journal_get_monotonic_usec(j, NULL, &boot_id); if (r >= 0) { if (previous_boot_id_valid && !sd_id128_equal(boot_id, previous_boot_id)) printf(ANSI_HIGHLIGHT_ON "----- Reboot -----" ANSI_HIGHLIGHT_OFF "\n"); previous_boot_id = boot_id; previous_boot_id_valid = true; } line ++; r = output_journal(j, arg_output, line, 0, flags); if (r < 0) goto finish; need_seek = true; } if (!arg_follow) break; r = sd_journal_wait(j, (uint64_t) -1); if (r < 0) { log_error("Couldn't wait for log event: %s", strerror(-r)); goto finish; } } if (arg_output == OUTPUT_JSON) fputs("\n]\n", stdout); finish: if (j) sd_journal_close(j); pager_close(); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }