Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add summary module for aggregating runtime information and internal metrics #365

Open
wants to merge 19 commits into
base: main
Choose a base branch
from

Conversation

simonsan
Copy link
Contributor

An informative summary system for aggregating and condensing data collected
from runtime checks, including warnings, issues, and operational metrics.

This system should provide end-users with a clear, concise summary of command
execution results without conflicting with existing error-handling standards.
In scenarios where execution cannot proceed due to a critical error, a
RusticError will be raised instead, and no summary will be provided.

Separation of Concerns

Critical runtime errors that prevent further execution are handled through the
existing RusticError system. The Summary will only collect information for
non-fatal events.

Compatibility with Existing Error Handling

Summaries must coexist with error propagation rules. They will not replace
the core behavior of error propagation but act as a complementary mechanism
for presenting non-fatal feedback.

User-Friendly Reporting

Summaries should aggregate detailed runtime information—such as warnings,
issues, and metrics — in a clear and condensed format for the end-user.

Aggregation & Condensation

Similar or repeated errors should be aggregated to avoid redundant information,
presenting users with a high-level overview.

…rnal metrics

Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com>
Copy link

codecov bot commented Nov 21, 2024

Codecov Report

Attention: Patch coverage is 54.65116% with 39 lines in your changes missing coverage. Please review.

Project coverage is 42.2%. Comparing base (e812ae1) to head (f30bb6e).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
crates/core/src/error/summary.rs 54.6% 39 Missing ⚠️
Additional details and impacted files
Files with missing lines Coverage Δ
crates/core/src/error.rs 67.5% <ø> (-2.0%) ⬇️
crates/core/src/error/summary.rs 54.6% <54.6%> (ø)

... and 22 files with indirect coverage changes

---- 🚨 Try these New Features:

Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com>
…nd update export logic

Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com>
Comment on lines +78 to +85
pub enum DisplayOptionKind {
#[default]
Issues,
Timing,
Metrics,
All,
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These could be bitflags or enumflags, but I'm unsure if that wouldn't be overengineering?

…ic method

Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com>
@simonsan simonsan requested review from aawsome and nardoor November 21, 2024 23:14
@simonsan simonsan added A-errors Area: error handling needs improvement C-enhancement Category: New feature or request A-api Area: Related to API design of rustic_core A-dx Area: Related to Developer Experience A-commands Area: Related to commands in `rustic_core` labels Nov 21, 2024
…ethods to use EcoString

Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com>
@simonsan simonsan added the S-waiting-for-review Status: PRs waiting for review label Nov 22, 2024
@simonsan
Copy link
Contributor Author

simonsan commented Nov 22, 2024

What's still missing is functionality to store different categories of issues, e.g. warnings or soft errors. And then to log them to the terminal.

TODO:

  • store different categories of issues (warnings, soft errors)
  • add matching logic to decide which log macro to use
  • add setting to Summary, that enables/disables logging on adding issues

Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com>
…ove logging

Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com>
Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com>
Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com>
Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com>
Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com>
… Summary

Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com>
…tional fields in Summary

Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com>
Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com>

use ecow::EcoString;

pub type Issues = BTreeMap<IssueCategory, BTreeMap<IssueScope, CondensedIssue>>;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is IssueScope needed, or do we want to deduplicated on some other stuff? We can also not use a BTreeMap here, but just a Vector.

pub type Issues = BTreeMap<IssueCategory, Vec<CondensedIssue>>;

Copy link
Contributor

Choose a reason for hiding this comment

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

Could IssueScope be a member of CondensedIssue?
So you use a Vec and still have a notion of IssueScope

…king logic

Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com>
Comment on lines +285 to +296
// ! TODO: Refactor this method to merge the context of each summary
// !
// ? How do we merge the context of each summary?
// ? We can't merge the context, as it's a unique identifier for each summary.
// ? We could add a new field to each CondensedIssue to store the context of the
// ? merged summaries.
// ?
// ? How do we merge the other fields? E.g. Timing, Metrics, etc.
pub fn merge(&mut self, other: Self) {
self.issues.extend(other.issues);
self.metrics.extend(other.metrics);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Use conflate and implement Merge, make sure we fulfil above requirements and make it as ergonomic as possible. Make sure deduplication works well also for edge cases. We want to be sure, that we can assess if a command soft errored (warnings are lower priority).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, conflate is actually behind the merge feature flag and doesn't make sense then to be used here.

Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com>
Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com>
Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com>

use ecow::EcoString;

pub type Issues = BTreeMap<IssueCategory, BTreeMap<IssueScope, CondensedIssue>>;
Copy link
Contributor

Choose a reason for hiding this comment

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

Could IssueScope be a member of CondensedIssue?
So you use a Vec and still have a notion of IssueScope

metrics: Metrics,

/// Display this data
display: HashSet<DisplayOptionKind>,
Copy link
Contributor

Choose a reason for hiding this comment

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

As I'm beginning to read through the code, I am not (yet) fully undertanding what DisplayOptionKind is about.
Could you detail it a bit more in the code-doc? (for instance in the enum's doc)

pub fn enable_log(&mut self) -> Self {
self.log_enabled = true;
self.clone()
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder what is the reason to use clone there?

The builder pattern usually is something like:

    pub fn enable_log(mut self) -> Self {
        self.log_enabled = true;
        self
    }

Comment on lines +208 to +224
_ = self
.issues
.entry(category)
.or_default()
.entry(scope)
.and_modify(|val| {
val.count += 1;
if val.root_cause.is_none() {
val.root_cause.clone_from(&root_cause);
}
})
.or_insert(CondensedIssue {
category,
message,
count: 1,
root_cause,
});
Copy link
Contributor

Choose a reason for hiding this comment

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

As I see it, when we get in the and_modify case, we loose the message.
Is that voluntary?

Same we might have != root_cause but we'll keep only one.

Wouldn't this lead to "wrong" reporting of some error A that happened N times, but in reality, A happened N1 times and B, C, D, E had the same scope and happened but their "message" and "root_cause" are lost.

I understand we want to aggregate and get a high level overview. But as I understand this, we could become misleading there.

Comment on lines +231 to +236
_ = self
.metrics
.entry(key.into())
.and_modify(|val| *val = value.clone())
.or_insert_with(|| value);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Here I see that metrics are erase on save.

I feel like this should be documented in the add method.

Maybe also this method should be renamed set_metric?


pub fn export_all(&mut self) -> bool {
self.display.insert(DisplayOptionKind::All)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

could you let me know of use cases where we want only some DisplayOptionKind and not some others?

Also I feel it's a bit weird that ALL is an enum value.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-api Area: Related to API design of rustic_core A-commands Area: Related to commands in `rustic_core` A-dx Area: Related to Developer Experience A-errors Area: error handling needs improvement C-enhancement Category: New feature or request S-waiting-for-review Status: PRs waiting for review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants