diff --git a/library/libstorage.h b/library/libstorage.h index 75463fc9..a45ee3c5 100644 --- a/library/libstorage.h +++ b/library/libstorage.h @@ -120,6 +120,13 @@ extern "C" StorageCallback callback, void *userData); + // Returns node metrics in the Logos openmetrics-compatible + // format (https://github.com/logos-co/openmetrics-module). + int storage_get_metrics( + void *ctx, + StorageCallback callback, + void *userData); + // Set the log level at run time. // `logLevel` can be one of: // TRACE, DEBUG, INFO, NOTICE, WARN, ERROR or FATAL diff --git a/library/libstorage.nim b/library/libstorage.nim index 609c919a..3da60ac7 100644 --- a/library/libstorage.nim +++ b/library/libstorage.nim @@ -185,6 +185,19 @@ proc storage_peer_id( return callback.okOrError(res, userData) +proc storage_get_metrics( + ctx: ptr StorageContext, callback: StorageCallback, userData: pointer +): cint {.dynlib, exportc.} = + initializeLibrary() + checkLibstorageParams(ctx, callback, userData) + + let reqContent = NodeInfoRequest.createShared(NodeInfoMsgType.METRICS) + let res = storage_context.sendRequestToStorageThread( + ctx, RequestType.INFO, reqContent, callback, userData + ) + + return callback.okOrError(res, userData) + ## Set the log level of the library at runtime. ## It uses updateLogLevel which is a synchronous proc and ## cannot be used inside an async context because of gcsafe issue. diff --git a/library/storage_thread_requests/requests/node_info_request.nim b/library/storage_thread_requests/requests/node_info_request.nim index 7e755a3a..1e2caed4 100644 --- a/library/storage_thread_requests/requests/node_info_request.nim +++ b/library/storage_thread_requests/requests/node_info_request.nim @@ -5,6 +5,8 @@ import chronos import chronicles import confutils import codexdht/discv5/spr +import metrics +import ../../logosmetrics import ../../../storage/conf import ../../../storage/rest/json import ../../../storage/node @@ -18,6 +20,8 @@ type NodeInfoMsgType* = enum REPO SPR PEERID + # Not sure this belongs here but for now OK. + METRICS type NodeInfoRequest* = object operation: NodeInfoMsgType @@ -74,3 +78,6 @@ proc process*( error "Failed to get PEERID.", error = res.error return err($res.error) return res + of METRICS: + {.cast(gcsafe).}: + return ok($defaultRegistry.toJson()) diff --git a/tests/cbindings/storage.c b/tests/cbindings/storage.c index 354b81d9..5818b830 100644 --- a/tests/cbindings/storage.c +++ b/tests/cbindings/storage.c @@ -841,6 +841,36 @@ int check_toggle_private_queries(void *storage_ctx) return RET_OK; } +int check_get_metrics(void *storage_ctx) +{ + Resp *r = alloc_resp(); + char *res = NULL; + + if (storage_get_metrics(storage_ctx, (StorageCallback)callback, r) != RET_OK) + { + free_resp(r); + return RET_ERR; + } + + int ret = is_resp_ok(r, &res); + if (ret != RET_OK) + { + free(res); + return ret; + } + + // Checks that response contains a metric we are SURE must exist + if (strstr(res, "nim_gc_heap_instance_occupied_bytes") == NULL) + { + fprintf(stderr, "get_metrics missing expected metric\n"); + free(res); + return RET_ERR; + } + + free(res); + return RET_OK; +} + // TODO: implement check_fetch // It is a bit complicated because it requires two nodes // connected together to fetch from peers. @@ -894,6 +924,7 @@ int main(void) RUN_TEST(check_toggle_private_queries(storage_ctx)); RUN_TEST(update_log_level(storage_ctx, "TRACE")); + RUN_TEST(check_get_metrics(storage_ctx)); RUN_TEST(cleanup(storage_ctx)); END_SUITE