commit a5d14ecf48f13307bf88ec3f8d50aa4a7c51b673
parent 4818ad787b21a02ba582c54b2e456c1afbbfdb4e
Author: triesap <137732411+triesap@users.noreply.github.com>
Date: Fri, 8 Aug 2025 18:14:55 +0000
Edit `indexer` adding audit feature to enable events logging.
Diffstat:
6 files changed, 119 insertions(+), 7 deletions(-)
diff --git a/crates/indexer/Cargo.toml b/crates/indexer/Cargo.toml
@@ -18,4 +18,8 @@ thiserror = "1.0"
tokio = { version = "1", features = ["full"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["fmt", "env-filter"] }
-tracing-appender = "0.2"
-\ No newline at end of file
+tracing-appender = "0.2"
+
+[features]
+default = []
+audit = []
diff --git a/crates/indexer/src/audit.rs b/crates/indexer/src/audit.rs
@@ -0,0 +1,74 @@
+#![cfg(feature = "audit")]
+
+use tracing::info;
+
+use crate::relay::event::RelayIndexerEvent;
+use radroots_common::models::events::{RadrootsListingEvent, RadrootsMetadataEvent};
+
+static AUDIT_PUBLIC_KEY: Option<&'static str> = option_env!("AUDIT_PUBLIC_KEY");
+
+#[inline]
+fn matches(pk: &str) -> bool {
+ match AUDIT_PUBLIC_KEY {
+ Some(w) => pk == w,
+ None => false,
+ }
+}
+
+#[inline]
+pub fn log_indexer_event(idx: &RelayIndexerEvent) {
+ if !matches(&idx.author) {
+ return;
+ }
+
+ let tags_json = match serde_json::to_string(&idx.tags) {
+ Ok(json) => json,
+ Err(_) => String::from("Error serializing tags"),
+ };
+ info!(
+ target: "audit",
+ kind = idx.kind.as_u64(),
+ id = %idx.id,
+ author = %idx.author,
+ created_at = idx.created_at,
+ tags = %tags_json,
+ content = %idx.content,
+ "AUDIT: relay indexer event"
+ );
+}
+
+#[inline]
+pub fn log_metadata_event(evt: &RadrootsMetadataEvent) {
+ if !matches(&evt.event.author) {
+ return;
+ }
+ if let Ok(json) = serde_json::to_string(evt) {
+ info!(
+ target = "audit",
+ kind = evt.event.kind,
+ id = %evt.event.id,
+ author = %evt.event.author,
+ created_at = evt.event.created_at,
+ processed_json = %json,
+ "AUDIT: processed metadata"
+ );
+ }
+}
+
+#[inline]
+pub fn log_listing_event(evt: &RadrootsListingEvent) {
+ if !matches(&evt.event.author) {
+ return;
+ }
+ if let Ok(json) = serde_json::to_string(evt) {
+ info!(
+ target = "audit",
+ kind = evt.event.kind,
+ id = %evt.event.id,
+ author = %evt.event.author,
+ created_at = evt.event.created_at,
+ processed_json = %json,
+ "AUDIT: processed listing"
+ );
+ }
+}
diff --git a/crates/indexer/src/domain/indexer/models/listing.rs b/crates/indexer/src/domain/indexer/models/listing.rs
@@ -11,6 +11,7 @@ use std::{collections::BTreeMap, fs, path::PathBuf};
use tracing::{instrument, warn};
use crate::{
+ audit,
domain::{
events::ToRadrootsListingEvent,
indexer::{
@@ -69,6 +70,7 @@ impl EventIndexes for EventListingIndexes {
for raw in raw_events {
match raw.clone().to_radroots_listing_event() {
Ok(evt) => {
+ audit::log_listing_event(&evt);
let id = evt.event.id.clone();
let country_code = evt.data.location_country.to_lowercase();
diff --git a/crates/indexer/src/domain/indexer/models/metadata.rs b/crates/indexer/src/domain/indexer/models/metadata.rs
@@ -9,6 +9,7 @@ use std::{collections::BTreeMap, fs, path::PathBuf};
use tracing::{instrument, warn};
use crate::{
+ audit,
domain::{
events::ToRadrootsMetadataEvent,
indexer::{
@@ -68,6 +69,7 @@ impl EventIndexes for EventMetadataIndexes {
for raw in raw_events {
match raw.clone().to_radroots_metadata_event() {
Ok(evt) => {
+ audit::log_metadata_event(&evt);
let id = evt.event.id.clone();
let author = evt.event.author.clone();
events.push(evt.clone());
diff --git a/crates/indexer/src/lib.rs b/crates/indexer/src/lib.rs
@@ -20,6 +20,17 @@ pub mod relay {
pub mod event;
pub mod record;
}
+
+#[cfg(feature = "audit")]
+pub mod audit;
+
+#[cfg(not(feature = "audit"))]
+pub mod audit {
+ pub fn log_indexer_event(_: &crate::relay::event::RelayIndexerEvent) {}
+ pub fn log_metadata_event(_: &radroots_common::models::events::RadrootsMetadataEvent) {}
+ pub fn log_listing_event(_: &radroots_common::models::events::RadrootsListingEvent) {}
+}
+
use crate::{
domain::indexer::{
kind::IndexerEventKind,
@@ -78,6 +89,7 @@ pub async fn run(settings: Settings) -> Result<()> {
let mut records_kind: HashMap<IndexerEventKind, Vec<RelayIndexerEvent>> = HashMap::new();
for rec in records.into_iter() {
let iev = RelayIndexerEvent::try_from(rec)?;
+ audit::log_indexer_event(&iev);
records_kind.entry(iev.kind).or_default().push(iev);
}
diff --git a/crates/indexer/src/telemetry.rs b/crates/indexer/src/telemetry.rs
@@ -1,9 +1,12 @@
use std::path::Path;
use tracing_appender::rolling;
-use tracing_subscriber::{fmt, prelude::*, registry::Registry, EnvFilter};
+use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry};
+
+#[cfg(feature = "audit")]
+use tracing_subscriber::filter::Targets;
pub fn init(logs_dir: impl AsRef<Path>) {
- let file_appender = rolling::daily(logs_dir, concat!(env!("CARGO_PKG_NAME"), ".log"));
+ let file_appender = rolling::daily(&logs_dir, concat!(env!("CARGO_PKG_NAME"), ".log"));
let (file_writer, guard) = tracing_appender::non_blocking(file_appender);
std::mem::forget(guard);
@@ -14,9 +17,25 @@ pub fn init(logs_dir: impl AsRef<Path>) {
.with_ansi(false)
.with_target(false);
- Registry::default()
+ let subscriber = Registry::default()
.with(EnvFilter::from_default_env())
.with(stdout_layer)
- .with(file_layer)
- .init();
+ .with(file_layer);
+
+ #[cfg(feature = "audit")]
+ let subscriber = {
+ let audit_app = rolling::daily(&logs_dir, "audit.log");
+ let (audit_writer, audit_guard) = tracing_appender::non_blocking(audit_app);
+ std::mem::forget(audit_guard);
+
+ let audit_layer = fmt::layer()
+ .with_writer(audit_writer)
+ .with_ansi(false)
+ .with_target(true)
+ .with_filter(Targets::new().with_target("audit", tracing::Level::INFO));
+
+ subscriber.with(audit_layer)
+ };
+
+ subscriber.init();
}