Skip to content

Commit

Permalink
Added logging of the reasoner input
Browse files Browse the repository at this point in the history
  • Loading branch information
Lut99 committed Oct 17, 2024
1 parent 586b57c commit 419645d
Show file tree
Hide file tree
Showing 9 changed files with 170 additions and 55 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

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

50 changes: 38 additions & 12 deletions lib/loggers/file/src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// Created:
// 10 Oct 2024, 14:16:24
// Last edited:
// 17 Oct 2024, 11:26:13
// 17 Oct 2024, 13:17:01
// Auto updated?
// Yes
//
Expand All @@ -20,6 +20,7 @@ use std::path::PathBuf;

use enum_debug::EnumDebug as _;
use serde::Serialize;
use serde_json::Value;
use spec::auditlogger::AuditLogger;
use spec::context::Context;
use spec::reasonerconn::ReasonerResponse;
Expand Down Expand Up @@ -151,7 +152,7 @@ impl FileLogger {
///
/// # Errors
/// This function errors if we failed to perform the logging completely (i.e., either write or flush).
async fn log<T: Clone + Debug + Serialize>(&self, stmt: LogStatement<'_, T>) -> Result<(), Error> {
async fn log(&self, stmt: LogStatement<'_>) -> Result<(), Error> {
// Step 1: Open the log file
let mut handle: File = if !self.path.exists() {
debug!("Creating new log file at '{}'...", self.path.display());
Expand Down Expand Up @@ -207,13 +208,13 @@ impl AuditLogger for FileLogger {
{
async move {
// Serialize the context first
let ctx: String = match serde_json::to_string_pretty(context) {
let context: Value = match serde_json::to_value(context) {
Ok(ctx) => ctx,
Err(err) => return Err(Error::LogStatementSerialize { kind: "LogStatement::Context".into(), err }),
};

// Log it
self.log::<()>(LogStatement::Context { context: Cow::Owned(ctx) }).await?;
self.log(LogStatement::Context { context }).await?;
self.logged_context = true;
Ok(())
}
Expand All @@ -236,18 +237,43 @@ impl AuditLogger for FileLogger {
}

// Serialize the response first
let res: ReasonerResponse<String> = match response {
let response: Value = match serde_json::to_value(&match response {
ReasonerResponse::Success => ReasonerResponse::Success,
ReasonerResponse::Violated(r) => ReasonerResponse::Violated(r.to_string()),
ReasonerResponse::Violated(reasons) => ReasonerResponse::Violated(reasons.to_string()),
}) {
Ok(res) => res,
Err(err) => return Err(Error::LogStatementSerialize { kind: "LogStatement::ReasonerResponse".into(), err }),
};

// Log it
self.log(LogStatement::ReasonerResponse {
reference: Cow::Borrowed(reference),
response: Cow::Borrowed(&res),
raw: raw.map(Cow::Borrowed),
})
.await
self.log(LogStatement::ReasonerResponse { reference: Cow::Borrowed(reference), response, raw: raw.map(Cow::Borrowed) }).await
}
}

#[inline]
fn log_question<'a, S, Q>(&'a mut self, reference: &'a str, state: &'a S, question: &'a Q) -> impl 'a + Future<Output = Result<(), Self::Error>>
where
S: Serialize,
Q: Serialize,
{
async move {
#[cfg(debug_assertions)]
if !self.logged_context {
tracing::warn!("Logging reasoner response without having logged the reasoner context; please call FileLogger::log_context() first.");
}

// Serialize the state & question first
let state: Value = match serde_json::to_value(state) {
Ok(res) => res,
Err(err) => return Err(Error::LogStatementSerialize { kind: "LogStatement::ReasonerConsult".into(), err }),
};
let question: Value = match serde_json::to_value(question) {
Ok(res) => res,
Err(err) => return Err(Error::LogStatementSerialize { kind: "LogStatement::ReasonerConsult".into(), err }),
};

// Log it
self.log(LogStatement::ReasonerConsult { reference: Cow::Borrowed(reference), state, question }).await
}
}
}
12 changes: 7 additions & 5 deletions lib/loggers/file/src/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// Created:
// 10 Oct 2024, 14:24:22
// Last edited:
// 17 Oct 2024, 09:49:04
// 17 Oct 2024, 13:15:51
// Auto updated?
// Yes
//
Expand All @@ -16,15 +16,17 @@ use std::borrow::Cow;

use enum_debug::EnumDebug;
use serde::{Deserialize, Serialize};
use spec::reasonerconn::ReasonerResponse;
use serde_json::Value;


/***** LIBRARY *****/
/// Defines the internal representation of a log statement.
#[derive(Clone, Debug, Deserialize, EnumDebug, Serialize)]
pub enum LogStatement<'a, T: Clone> {
pub enum LogStatement<'a> {
/// Logging a reasoner context.
Context { context: Cow<'a, str> },
Context { context: Value },
/// Logging a question to a reasoner.
ReasonerConsult { reference: Cow<'a, str>, state: Value, question: Value },
/// Logging a reasoner response.
ReasonerResponse { reference: Cow<'a, str>, response: Cow<'a, ReasonerResponse<T>>, raw: Option<Cow<'a, str>> },
ReasonerResponse { reference: Cow<'a, str>, response: Value, raw: Option<Cow<'a, str>> },
}
20 changes: 19 additions & 1 deletion lib/loggers/no-op/src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// Created:
// 10 Oct 2024, 14:46:33
// Last edited:
// 17 Oct 2024, 11:23:08
// 17 Oct 2024, 13:14:34
// Auto updated?
// Yes
//
Expand All @@ -16,6 +16,7 @@ use std::convert::Infallible;
use std::fmt::Display;
use std::future::Future;

use serde::Serialize;
use spec::auditlogger::AuditLogger;
use spec::context::Context;
use spec::reasonerconn::ReasonerResponse;
Expand Down Expand Up @@ -65,4 +66,21 @@ impl AuditLogger for MockLogger {
Ok(())
}
}

#[inline]
fn log_question<'a, S, Q>(
&'a mut self,
_reference: &'a str,
_state: &'a S,
_question: &'a Q,
) -> impl 'a + Future<Output = Result<(), Self::Error>>
where
S: Serialize,
Q: Serialize,
{
async move {
println!("AUDIT LOG: log_question");
Ok(())
}
}
}
27 changes: 21 additions & 6 deletions lib/reasoners/eflint-json/src/reasonerconn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// Created:
// 09 Oct 2024, 15:52:06
// Last edited:
// 17 Oct 2024, 12:12:54
// 17 Oct 2024, 13:59:28
// Auto updated?
// Yes
//
Expand Down Expand Up @@ -48,6 +48,13 @@ pub enum Error<R, S, Q> {
#[source]
err: Trace,
},
/// Failed to log the question to the given logger.
#[error("Failed to log the question to {to}")]
LogQuestion {
to: &'static str,
#[source]
err: Trace,
},
/// Failed to receive a [`ResponsePhrases`] to the remote reasoner (as raw).
#[error("Failed to fetch reply from remote reasoner at {addr:?}")]
ReasonerResponse {
Expand Down Expand Up @@ -124,7 +131,7 @@ impl spec::context::Context for Context {
}

/// Defines the eFLINT reasoner state to submit to it.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct State<S> {
/// The policy used.
pub policy: Vec<Phrase>,
Expand Down Expand Up @@ -181,8 +188,12 @@ impl<R, S, Q> EFlintJsonReasonerConnector<R, S, Q> {
Q::Error: 'static,
{
async move {
logger.log_context("").await.map_err(|err| Error::LogContext { to: std::any::type_name::<L>(), err: err.freeze() })?;
Ok(Self { addr: addr.into(), reason_handler: handler, _state: PhantomData, _question: PhantomData })
let addr: String = addr.into();
logger
.log_context(&Context { addr: addr.clone() })
.await
.map_err(|err| Error::LogContext { to: std::any::type_name::<L>(), err: err.freeze() })?;
Ok(Self { addr, reason_handler: handler, _state: PhantomData, _question: PhantomData })
}
}
}
Expand All @@ -191,9 +202,9 @@ where
R: ReasonHandler,
R::Reason: Display,
R::Error: 'static,
S: EFlintable,
S: EFlintable + Serialize,
S::Error: 'static,
Q: EFlintable,
Q: EFlintable + Serialize,
Q::Error: 'static,
{
type Error = Error<R::Error, S::Error, Q::Error>;
Expand All @@ -213,6 +224,10 @@ where
async move {
// NOTE: Using `#[instrument]` adds some unnecessary trait bounds on `S` and such.
let _span = span!(Level::INFO, "EFlintJsonReasonerConnector::consult", reference = logger.reference()).entered();
logger
.log_question(&state, &question)
.await
.map_err(|err| Error::LogQuestion { to: std::any::type_name::<SessionedAuditLogger<L>>(), err: err.freeze() })?;

// Build the full policy
debug!("Building full policy...");
Expand Down
2 changes: 2 additions & 0 deletions lib/reasoners/no-op/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ license.workspace = true


[dependencies]
serde = "1.0.204"
thiserror = "1.0.61"
tracing = "0.1.40"

error-trace = { git = "https://github.com/Lut99/error-trace-rs", tag = "v3.1.0" }
Expand Down
57 changes: 30 additions & 27 deletions lib/reasoners/no-op/src/reasonerconn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,49 +4,43 @@
// Created:
// 10 Oct 2024, 16:21:09
// Last edited:
// 17 Oct 2024, 09:50:23
// 17 Oct 2024, 13:56:10
// Auto updated?
// Yes
//
// Description:
//! <Todo>
//

use std::error;
use std::fmt::{Display, Formatter, Result as FResult};
use std::future::Future;
use std::marker::PhantomData;

use error_trace::{ErrorTrace as _, Trace};
use serde::Serialize;
use spec::auditlogger::SessionedAuditLogger;
use spec::reasonerconn::ReasonerResponse;
use spec::{AuditLogger, ReasonerConnector};
use thiserror::Error;
use tracing::{debug, span, Level};


/***** ERRORS *****/
#[derive(Debug)]
#[derive(Debug, Error)]
pub enum Error {
/// Failed to log the reasoner's response to the given logger.
LogResponse { to: &'static str, err: Trace },
}
impl Display for Error {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
use Error::*;
match self {
LogResponse { to, .. } => write!(f, "Failed to log the reasoner's response to {to}"),
}
}
}
impl error::Error for Error {
#[inline]
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
use Error::*;
match self {
LogResponse { err, .. } => Some(err),
}
}
#[error("Failed to log the reasoner's response to {to}")]
LogResponse {
to: &'static str,
#[source]
err: Trace,
},
/// Failed to log the question to the given logger.
#[error("Failed to log the question to {to}")]
LogQuestion {
to: &'static str,
#[source]
err: Trace,
},
}


Expand All @@ -73,16 +67,19 @@ impl<Q> NoOpReasonerConnector<Q> {
#[inline]
pub fn new() -> Self { Self { _question: PhantomData } }
}
impl<Q> ReasonerConnector for NoOpReasonerConnector<Q> {
impl<Q> ReasonerConnector for NoOpReasonerConnector<Q>
where
Q: Serialize,
{
type Error = Error;
type Question = Q;
type Reason = ();
type State = ();

fn consult<L>(
&self,
_state: Self::State,
_question: Self::Question,
state: Self::State,
question: Self::Question,
logger: &mut SessionedAuditLogger<L>,
) -> impl Future<Output = Result<ReasonerResponse<Self::Reason>, Self::Error>>
where
Expand All @@ -91,9 +88,15 @@ impl<Q> ReasonerConnector for NoOpReasonerConnector<Q> {
async move {
// NOTE: Using `#[instrument]` adds some unnecessary trait bounds on `S` and such.
let _span = span!(Level::INFO, "NoOpReasonerConnector::consult", reference = logger.reference()).entered();
debug!("NoOpReasonerConnector: request received");

// Log that the question has been asked
logger
.log_question(&state, &question)
.await
.map_err(|err| Error::LogQuestion { to: std::any::type_name::<SessionedAuditLogger<L>>(), err: err.freeze() })?;

// Log the reasoner has been called
debug!("NoOpReasonerConnector: request received");
logger
.log_response::<u8>(&ReasonerResponse::Success, None)
.await
Expand Down
Loading

0 comments on commit 419645d

Please sign in to comment.