Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
cmake_minimum_required(VERSION 3.14)
project(Libp2pModulePlugin LANGUAGES CXX)

find_package(nlohmann_json REQUIRED)

if(DEFINED ENV{LOGOS_MODULE_BUILDER_ROOT})
include($ENV{LOGOS_MODULE_BUILDER_ROOT}/cmake/LogosModule.cmake)
else()
Expand Down Expand Up @@ -31,4 +33,6 @@ logos_module(
tinycbor
)

target_link_libraries(libp2p_module_module_plugin PUBLIC nlohmann_json::nlohmann_json)

add_subdirectory(tutorial)
8 changes: 4 additions & 4 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 21 additions & 10 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

inputs = {
logos-module-builder.url = "github:logos-co/logos-module-builder";
libp2p.url = "github:vacp2p/nim-libp2p/fix/cbind/nim-ffi-bump";
libp2p.url = "github:vacp2p/nim-libp2p/master";

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't fix this to master, as changes can spill here unexpectedly

Suggested change
libp2p.url = "github:vacp2p/nim-libp2p/master";
libp2p.url = "github:vacp2p/nim-libp2p/fix/cbind/nim-ffi-bump";

or the commit that was merged in master

Suggested change
libp2p.url = "github:vacp2p/nim-libp2p/master";
libp2p.url = "github:vacp2p/nim-libp2p/a760255635529adbc2e8f198b8b53ba13396c4ec";

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changes can't spill here unexpectedly as it is fixed to master, with rev a70c615c287a94e1134f45c05c18c338c7a3bc8f.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see flake.lock file

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! but when doing nix flake update to update some other dep this will also update nim-libp2p to latest master, which might not be what we want

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why would it be okay for other deps and not for nim-libp2p dep?

@gmelodie gmelodie Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's say we need to update logos core, but nim-libp2p has some breaking changes that have not been ported to cbind yet.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nim-libp2p has some breaking changes that have not been ported to cbind yet

could never happen. every push to nim-libp2p master has to pass CI. if nim-libp2p code brakes cbind CI that PR will not get through.

ether way, even when we assume that, that case can happen, those are exceptional cases. meaning that by default we want default behavior, which is nix flake update to updated everything. and exceptional cases are dealt with an exception. in this hypothetical case, one would still do nix flake update and manually rivert changes related to nim-libp2p.


openmetrics-module = {
url = "github:logos-co/openmetrics-module";
Expand All @@ -17,9 +17,28 @@

outputs = inputs@{ logos-module-builder, ... }:
let
nixpkgs = logos-module-builder.inputs.nixpkgs;
systems = [ "aarch64-darwin" "x86_64-darwin" "aarch64-linux" "x86_64-linux" ];

forEachSystem = f: builtins.listToAttrs (map (system: {
name = system;
value = f system;
}) systems);

libp2pInputs = {
packages = forEachSystem (system: {
cbind = inputs.libp2p.packages.${system}.cbind.overrideAttrs (old: {
buildPhase = builtins.replaceStrings
[ "--threads:on --opt:size --noMain --mm:refc --d:metrics" ]
[ "--threads:on --opt:size --noMain --mm:refc --d:metrics -d:chronicles_runtime_filtering=on" ]
old.buildPhase;
});
});
};

externalLibInputs = {
libp2p = {
input = inputs.libp2p;
input = libp2pInputs;
packages.default = "cbind";
};
};
Expand All @@ -34,14 +53,6 @@
};
};

nixpkgs = logos-module-builder.inputs.nixpkgs;
systems = [ "aarch64-darwin" "x86_64-darwin" "aarch64-linux" "x86_64-linux" ];

forEachSystem = f: builtins.listToAttrs (map (system: {
name = system;
value = f system;
}) systems);

# Pre-resolved store paths for the two .lgx bundles the e2e installs.
e2eEnv = system: {
LIBP2P_LGX_DIR = "${module.packages.${system}.lgx}";
Expand Down
7 changes: 7 additions & 0 deletions src/plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ void reapLateContext(std::future<SyncResult> f) {
}

constexpr char kModuleVersion[] = "1.0.0";

std::atomic<int64_t> g_requestedLogLevel{LOG_LEVEL_DEBUG};
}

void Libp2pModuleImpl::publishEmitEvent() {
Expand Down Expand Up @@ -176,6 +178,7 @@ StdLogosResult Libp2pModuleImpl::createContext() {
// identity; a supplied key gives a stable peer id across restarts.
m_libp2pConfig.privKey =
NimFfiBytes{m_privKey.empty() ? nullptr : m_privKey.data(), m_privKey.size()};
m_libp2pConfig.logLevel = g_requestedLogLevel.load();

auto r = spawnContext(m_libp2pConfig);
if (!r.ok) {
Expand Down Expand Up @@ -213,6 +216,10 @@ StdLogosResult Libp2pModuleImpl::createNode(const std::string& config) {
return createContext();
}

void Libp2pModuleImpl::setLogLevel(LogLevel level) {
g_requestedLogLevel.store(static_cast<int64_t>(level));
}

void Libp2pModuleImpl::destroyContext() {
if (!ctx) {
return;
Expand Down
25 changes: 23 additions & 2 deletions src/plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,21 @@ struct SyncResult {
LibP2PCtx* newCtx = nullptr;
};

// libp2p logs treat levels as inclusive minimum thresholds:
// `Trace` emits trace and above, `Debug` emits debug and above, etc.
// `None` is the lowest threshold, so it emits all logs; use `Fatal` for the
// quietest built-in threshold.
enum class LogLevel : int64_t {
None = LOG_LEVEL_NONE, // All logs.
Trace = LOG_LEVEL_TRACE, // Trace and above.
Debug = LOG_LEVEL_DEBUG, // Debug and above.
Info = LOG_LEVEL_INFO, // Info and above.
Notice = LOG_LEVEL_NOTICE, // Notice and above.
Warn = LOG_LEVEL_WARN, // Warn and above.
Error = LOG_LEVEL_ERROR, // Error and above.
Fatal = LOG_LEVEL_FATAL, // Fatal only.
};

enum class KeyScheme : int64_t {
Rsa = KEY_SCHEME_RSA,
Ed25519 = KEY_SCHEME_ED25519,
Expand Down Expand Up @@ -141,6 +156,8 @@ class Libp2pModuleImpl {

std::function<void(const std::string& eventName, const std::string& data)> emitEvent;

static void setLogLevel(LogLevel level);

bool ok();
StdLogosResult status();

Expand Down Expand Up @@ -307,8 +324,8 @@ class Libp2pModuleImpl {
// Same dance without the context check, for the `{.ffiStatic.}` bindings:
// they take no ctx and run on the library's own static context.
template <class Invoke, class Transform>
StdLogosResult callStaticWith(const char* errPrefix, Invoke&& invoke, Transform&& transform,
int awaitMs = kDefaultOpTimeoutMs) {
static StdLogosResult callStaticWith(const char* errPrefix, Invoke&& invoke, Transform&& transform,
int awaitMs = kDefaultOpTimeoutMs) {
auto* p = new SyncPromise();
auto f = p->get_future();
int ret = invoke(p);
Expand All @@ -328,3 +345,7 @@ class Libp2pModuleImpl {
return transform(r);
}
};

inline void setLogLevel(LogLevel level) {
return Libp2pModuleImpl::setLogLevel(level);
}
43 changes: 41 additions & 2 deletions tutorial/docs/tutorial_0_introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,30 @@ These programs are examples, not long-running services. When a required
operation fails, they print a useful error message to `stderr` and return
`1`. Successful tutorials print progress to `stdout` and return `0`.

The `stdout` stream can be noisy because logs from the wrapped C binding
are also included. This is tracked in [issue #79](https://github.com/logos-co/logos-libp2p-module/issues/79).
## Controlling libp2p Logs

The wrapped libp2p binding can emit runtime logs. Tutorials set the log
level to `LogLevel::Fatal` by default so `stdout` only shows the tutorial's
own progress messages during normal runs. Choose another level such as
`LogLevel::Info`, `LogLevel::Debug`, or `LogLevel::Trace` when you need more
detail while debugging:

```cpp
setLogLevel(LogLevel::Debug);
// ... or
Libp2pModuleImpl::setLogLevel(LogLevel::Debug);
```

Log levels are inclusive minimum thresholds: `LogLevel::Trace` emits trace
and above, `LogLevel::Debug` emits debug and above, and so on.
`LogLevel::None` is the lowest threshold, so it emits all logs; it does not
disable logging. Use `LogLevel::Fatal` for the quietest built-in threshold.

In your own application, `LogLevel::Error` is often a useful default.
It keeps normal output quiet while still surfacing conditions
that may indicate libp2p is misbehaving or that your integration code needs an
adjustment. Some error logs describe remote-peer behavior, retries, or
recoverable internal state, so they may not require any action from your side.

## Convert JSON Values Explicitly

Expand Down Expand Up @@ -80,6 +102,9 @@ int main()
{
printf("=== Tutorial 0: Introduction and Common Patterns ===\n\n");

// Silence logs from wrapped library.
setLogLevel(LogLevel::Fatal);

```

## Step 1: Create and start a node
Expand Down Expand Up @@ -181,6 +206,20 @@ tutorials with this command and then run it again:
```bash
nix --extra-experimental-features 'nix-command flakes' develop --command ./tutorial/build_tutorials.sh
```

## Exercise: Enable libp2p debug logs

Change this tutorial's log level from `LogLevel::None` to
`LogLevel::Debug`:

```cpp
setLogLevel(LogLevel::Debug);
```

Compile the tutorial binaries again, using the same command from above.

Run tutorial 0 again. You should now see libp2p debug logs in `stdout`
alongside the tutorial's own progress messages.
---

<p align="center"><a href="tutorial_1_node_lifecycle.md">Creating and Starting a libp2p Node &rarr;</a></p>
2 changes: 2 additions & 0 deletions tutorial/docs/tutorial_10_peerstore.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ int main()
{
printf("=== Tutorial 10: Peer Store Management ===\n\n");

setLogLevel(LogLevel::Fatal);

```

## Step 1: Create two nodes
Expand Down
2 changes: 2 additions & 0 deletions tutorial/docs/tutorial_11_circuit_relay.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ int main()
{
printf("=== Tutorial 11: Circuit Relay ===\n\n");

setLogLevel(LogLevel::Fatal);

```

## Step 1: Create three nodes
Expand Down
11 changes: 9 additions & 2 deletions tutorial/docs/tutorial_1_node_lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,18 @@ Every program starts by including the module's single public header - `"plugin.h
#include <string>
#include "plugin.h"

int main()
{
printf("=== Tutorial 1: Creating and Starting a libp2p Node ===\n\n");

setLogLevel(LogLevel::Fatal);

```

The main class we work with is `Libp2pModuleImpl`. Let's create one with
default options:

```cpp
int main()
{
// Create a libp2p node with default configuration.
// By default it listens on 127.0.0.1 with a random port (tcp/0).
Libp2pModuleImpl node;
Expand Down Expand Up @@ -111,6 +116,8 @@ Always clean up by stopping the node when you're done.
node.stop();
printf("Node stopped\n");

printf("\n=== Tutorial 1 Complete ===\n");

return 0;
}

Expand Down
32 changes: 18 additions & 14 deletions tutorial/docs/tutorial_2_custom_config.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ provide a custom address in the `addrs` field.

int main()
{
printf("=== Tutorial 2: Custom Node Configuration ===\n\n");

setLogLevel(LogLevel::Fatal);

```

## Method 1: Configure via C++ struct
Expand Down Expand Up @@ -156,6 +160,20 @@ supplied via `Libp2pModuleOptions::fromJson()`.

```

## Summary

In this tutorial you learned:
- How to configure a node with a fixed port
- How to control connection limits
- How to pass options via C++ struct or JSON
- How to verify the node's actual bound addresses

## Run tutorial

```bash
./build/tutorial/tutorial_2_custom_config
```

## Exercise: Try different configurations

Experiment with these variations:
Expand All @@ -171,20 +189,6 @@ options.addrs = {
"/ip4/0.0.0.0/tcp/9094"
};
```

## Summary

In this tutorial you learned:
- How to configure a node with a fixed port
- How to control connection limits
- How to pass options via C++ struct or JSON
- How to verify the node's actual bound addresses

## Run tutorial

```bash
./build/tutorial/tutorial_2_custom_config
```
---

<p align="center"><a href="tutorial_1_node_lifecycle.md">&larr; Creating and Starting a libp2p Node</a> &nbsp;|&nbsp; <a href="tutorial_3_connecting_peers.md">Connecting Peers and Exchanging Data &rarr;</a></p>
2 changes: 2 additions & 0 deletions tutorial/docs/tutorial_3_connecting_peers.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ int main()
{
printf("=== Tutorial 3: Connecting Peers ===\n\n");

setLogLevel(LogLevel::Fatal);

```

## Step 1: Create and start two nodes
Expand Down
2 changes: 2 additions & 0 deletions tutorial/docs/tutorial_4_custom_protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ int main()
{
printf("=== Tutorial 4: Custom Protocol Handlers ===\n\n");

setLogLevel(LogLevel::Fatal);

```

## Step 1: Create and start two nodes
Expand Down
2 changes: 2 additions & 0 deletions tutorial/docs/tutorial_5_kademlia_basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ int main()
{
printf("=== Tutorial 5: Kademlia DHT Basics ===\n\n");

setLogLevel(LogLevel::Fatal);

```

## Step 1: Create two nodes
Expand Down
2 changes: 2 additions & 0 deletions tutorial/docs/tutorial_6_kademlia_providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ with the provider API.
int main()
{
printf("=== Tutorial 6: Kademlia Provider Records ===\n\n");

setLogLevel(LogLevel::Fatal);

```

Expand Down
2 changes: 2 additions & 0 deletions tutorial/docs/tutorial_7_gossipsub_polling.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ int main()
{
printf("=== Tutorial 7: GossipSub - Polling for Messages ===\n\n");

setLogLevel(LogLevel::Fatal);

```

## Step 1: Create two nodes with GossipSub enabled
Expand Down
2 changes: 2 additions & 0 deletions tutorial/docs/tutorial_8_gossipsub_event_callback.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ int main()
{
printf("=== Tutorial 8: GossipSub - Event Callback Messages ===\n\n");

setLogLevel(LogLevel::Fatal);

```

## Step 1: Create two nodes with GossipSub enabled
Expand Down
2 changes: 2 additions & 0 deletions tutorial/docs/tutorial_9_service_discovery.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ int main()
{
printf("=== Tutorial 9: Service Discovery ===\n\n");

setLogLevel(LogLevel::Fatal);

```

## Step 1: Create a bootstrap node
Expand Down
Loading
Loading