예제 #1
0
static int journal_get_realtime_usec (lua_State *L) {
	sd_journal *j = check_journal(L, 1);
	uint64_t usec;
	int err = sd_journal_get_realtime_usec(j, &usec);
	if (err != 0) return handle_error(L, -err);
	lua_pushuint64(L, usec);
	return 1;
}
예제 #2
0
파일: logs-show.c 프로젝트: floppym/systemd
static int output_timestamp_realtime(FILE *f, sd_journal *j, OutputMode mode, OutputFlags flags, const char *realtime) {
        char buf[MAX(FORMAT_TIMESTAMP_MAX, 64)];
        struct tm *(*gettime_r)(const time_t *, struct tm *);
        struct tm tm;
        uint64_t x;
        time_t t;
        int r;

        assert(f);
        assert(j);

        if (realtime)
                r = safe_atou64(realtime, &x);
        if (!realtime || r < 0 || !VALID_REALTIME(x))
                r = sd_journal_get_realtime_usec(j, &x);
        if (r < 0)
                return log_error_errno(r, "Failed to get realtime timestamp: %m");

        if (IN_SET(mode, OUTPUT_SHORT_FULL, OUTPUT_WITH_UNIT)) {
                const char *k;

                if (flags & OUTPUT_UTC)
                        k = format_timestamp_utc(buf, sizeof(buf), x);
                else
                        k = format_timestamp(buf, sizeof(buf), x);
                if (!k) {
                        log_error("Failed to format timestamp: %"PRIu64, x);
                        return -EINVAL;
                }

        } else {
                char usec[7];

                gettime_r = (flags & OUTPUT_UTC) ? gmtime_r : localtime_r;
                t = (time_t) (x / USEC_PER_SEC);

                switch (mode) {

                case OUTPUT_SHORT_UNIX:
                        xsprintf(buf, "%10"PRI_TIME".%06"PRIu64, t, x % USEC_PER_SEC);
                        break;

                case OUTPUT_SHORT_ISO:
                        if (strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t, &tm)) <= 0) {
                                log_error("Failed to format ISO time");
                                return -EINVAL;
                        }
                        break;

                case OUTPUT_SHORT_ISO_PRECISE:
                        /* No usec in strftime, so we leave space and copy over */
                        if (strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S.xxxxxx%z", gettime_r(&t, &tm)) <= 0) {
                                log_error("Failed to format ISO-precise time");
                                return -EINVAL;
                        }
                        xsprintf(usec, "%06"PRI_USEC, x % USEC_PER_SEC);
                        memcpy(buf + 20, usec, 6);
                        break;

                case OUTPUT_SHORT:
                case OUTPUT_SHORT_PRECISE:

                        if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm)) <= 0) {
                                log_error("Failed to format syslog time");
                                return -EINVAL;
                        }

                        if (mode == OUTPUT_SHORT_PRECISE) {
                                size_t k;

                                assert(sizeof(buf) > strlen(buf));
                                k = sizeof(buf) - strlen(buf);

                                r = snprintf(buf + strlen(buf), k, ".%06"PRIu64, x % USEC_PER_SEC);
                                if (r <= 0 || (size_t) r >= k) { /* too long? */
                                        log_error("Failed to format precise time");
                                        return -EINVAL;
                                }
                        }
                        break;

                default:
                        assert_not_reached("Unknown time format");
                }
        }

        fputs(buf, f);
        return (int) strlen(buf);
}
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);
    }
예제 #4
0
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;
}
예제 #5
0
/**
 * 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?");
}
예제 #6
0
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;
}