report: separate report generation from upload

Let's split report generation from uploading, as prepatory step for
adding signing for reports.

No real code changes, just moving things around.
This commit is contained in:
Lennart Poettering
2026-06-19 05:00:06 +02:00
parent d086eb6d2e
commit 0d9026c736
7 changed files with 96 additions and 50 deletions
+1
View File
@@ -6,6 +6,7 @@ executables += [
'public' : true,
'sources' : files(
'report.c',
'report-generate.c',
'report-upload.c',
),
},
+51
View File
@@ -0,0 +1,51 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-json.h"
#include "log.h"
#include "report.h"
#include "report-generate.h"
#include "time-util.h"
int context_build_report(Context *context, sd_json_variant **ret) {
int r;
/* Convert the variant array to a JSON report. */
assert(context);
assert(ret);
usec_t ts = now(CLOCK_REALTIME);
_cleanup_(sd_json_variant_unrefp) sd_json_variant *report = NULL;
r = sd_json_buildo(&report,
SD_JSON_BUILD_PAIR_STRING("mediaType", "application/vnd.io.systemd.report"),
SD_JSON_BUILD_PAIR("timestamp",
SD_JSON_BUILD_STRING(FORMAT_TIMESTAMP_STYLE(ts, TIMESTAMP_UTC))),
SD_JSON_BUILD_PAIR("metrics",
SD_JSON_BUILD_VARIANT_ARRAY(context->metrics, context->n_metrics)));
if (r < 0)
return log_error_errno(r, "Failed to build JSON data: %m");
*ret = TAKE_PTR(report);
return 0;
}
int context_generate_report(Context *context) {
int r;
assert(context);
/* Make a structured report and either print it or upload it. */
_cleanup_(sd_json_variant_unrefp) sd_json_variant *report = NULL;
r = context_build_report(context, &report);
if (r < 0)
return r;
r = sd_json_variant_dump(report, arg_json_format_flags, /* f= */ NULL, /* prefix= */ NULL);
if (r < 0)
return log_error_errno(r, "Failed to dump json object: %m");
return 0;
}
+8
View File
@@ -0,0 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "report.h"
int context_build_report(Context *context, sd_json_variant **ret);
int context_generate_report(Context *context);
+11 -43
View File
@@ -6,6 +6,8 @@
#include "errno-util.h"
#include "log.h"
#include "report.h"
#include "report-generate.h"
#include "report-upload.h"
#include "string-util.h"
#include "strv.h"
#include "time-util.h"
@@ -13,11 +15,12 @@
#include "varlink-util.h"
#include "version.h"
#define REPORT_UPLOAD_DIR "/run/systemd/report.upload"
#define SERVER_ANSWER_MAX (1U * 1024U * 1024U)
#if HAVE_LIBCURL
#include "curl-util.h"
#define SERVER_ANSWER_MAX (1*1024*1024u)
static size_t output_callback(char *buf,
size_t size,
size_t nmemb,
@@ -54,26 +57,6 @@ static size_t output_callback(char *buf,
}
#endif
static int build_json_report(Context *context, sd_json_variant **ret) {
/* Convert the variant array to a JSON report. */
assert(context);
assert(ret);
usec_t ts = now(CLOCK_REALTIME);
int r;
r = sd_json_buildo(ret,
SD_JSON_BUILD_PAIR_STRING("mediaType", "application/vnd.io.systemd.report"),
SD_JSON_BUILD_PAIR("timestamp",
SD_JSON_BUILD_STRING(FORMAT_TIMESTAMP_STYLE(ts, TIMESTAMP_UTC))),
SD_JSON_BUILD_PAIR("metrics",
SD_JSON_BUILD_VARIANT_ARRAY(context->metrics, context->n_metrics)));
if (r < 0)
return log_error_errno(r, "Failed to build JSON data: %m");
return 0;
}
static int http_upload_collected(Context *context, sd_json_variant *report) {
#if HAVE_LIBCURL
_cleanup_(curl_slist_free_allp) struct curl_slist *header = NULL;
@@ -235,9 +218,14 @@ static int execute_dir_reply(
return 0;
}
static int upload_collected(Context *context, sd_json_variant *report) {
int context_upload_report(Context *context) {
int r;
_cleanup_(sd_json_variant_unrefp) sd_json_variant *report = NULL;
r = context_build_report(context, &report);
if (r < 0)
return r;
if (arg_url)
return http_upload_collected(context, report);
@@ -267,23 +255,3 @@ static int upload_collected(Context *context, sd_json_variant *report) {
log_debug("Upload via %s finished successfully.", REPORT_UPLOAD_DIR);
return 0;
}
/* Make a structured report and either print it or upload it. */
int report_collected(Context *context) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *report = NULL;
int r;
r = build_json_report(context, &report);
if (r < 0)
return r;
if (context->action == ACTION_UPLOAD)
return upload_collected(context, report);
/* Just print the report for now. */
assert(context->action == ACTION_GENERATE);
r = sd_json_variant_dump(report, arg_json_format_flags, /* f= */ NULL, /* prefix= */ NULL);
if (r < 0)
return log_error_errno(r, "Failed to dump json object: %m");
return 0;
}
+6
View File
@@ -0,0 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "report.h"
int context_upload_report(Context *context);
+19 -3
View File
@@ -16,6 +16,8 @@
#include "path-lookup.h"
#include "recurse-dir.h"
#include "report.h"
#include "report-generate.h"
#include "report-upload.h"
#include "runtime-scope.h"
#include "set.h"
#include "sort-util.h"
@@ -656,10 +658,24 @@ static int verb_metrics(int argc, char *argv[], uintptr_t data, void *userdata)
if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m");
if (IN_SET(action, ACTION_GENERATE, ACTION_UPLOAD))
r = report_collected(&context);
else
switch (action) {
case ACTION_LIST_METRICS:
case ACTION_DESCRIBE_METRICS:
r = output_collected(&context);
break;
case ACTION_GENERATE:
r = context_generate_report(&context);
break;
case ACTION_UPLOAD:
r = context_upload_report(&context);
break;
default:
assert_not_reached();
}
if (r < 0)
return r;
}
-4
View File
@@ -9,8 +9,6 @@
#define REPORT_CERT_FILE CERTIFICATE_ROOT "/certs/systemd-report.pem"
#define REPORT_TRUST_FILE CERTIFICATE_ROOT "/ca/trusted.pem"
#define REPORT_UPLOAD_DIR "/run/systemd/report.upload"
extern sd_json_format_flags_t arg_json_format_flags;
extern char *arg_url, *arg_key, *arg_cert, *arg_trust;
extern char **arg_extra_headers;
@@ -36,5 +34,3 @@ typedef struct Context {
int upload_result;
struct iovec_wrapper upload_answer;
} Context;
int report_collected(Context *context);