#[path = "json/attachment.rs"]
mod attachment;
#[path = "json/helpers.rs"]
mod helpers;
#[path = "json/report.rs"]
mod report;
#[cfg(feature = "trace")]
#[path = "json/trace.rs"]
mod trace;
use core::error::Error;
use core::fmt::{self, Formatter, Write};
use crate::report::{Report, SeverityState};
use super::REPORT_JSON_SCHEMA_VERSION;
use super::ReportRenderOptions;
pub(super) use super::filtered_frames;
pub(super) use helpers::{
close_array, close_object, write_array_item_prefix, write_error_code, write_indent,
write_json_display, write_json_string, write_object_field,
};
pub(super) fn write_json_report<E, State>(
report: &Report<E, State>,
options: ReportRenderOptions,
f: &mut Formatter<'_>,
) -> fmt::Result
where
E: Error,
State: SeverityState,
{
let pretty = options.json_pretty;
let mut first = true;
let section_flags = calc_section_flags(report);
f.write_char('{')?;
write_object_field(f, pretty, 0, &mut first, "schema_version", |f| {
write_json_string(f, REPORT_JSON_SCHEMA_VERSION)
})?;
write_object_field(f, pretty, 0, &mut first, "error", |f| {
report::write_error_object(f, pretty, 1, report.inner())
})?;
if options.show_governance_section
&& (options.show_empty_sections || section_flags.has_metadata)
{
write_object_field(f, pretty, 0, &mut first, "metadata", |f| {
report::write_metadata_object(f, pretty, 1, report)
})?;
}
if (options.show_stack_trace_section || options.show_cause_chains_section)
&& (options.show_empty_sections || section_flags.has_diag_bag)
{
write_object_field(f, pretty, 0, &mut first, "diagnostic_bag", |f| {
report::write_diag_bag(f, pretty, 1, report, options)
})?;
}
#[cfg(feature = "trace")]
if options.show_trace_section && (options.show_empty_sections || !report.trace().is_empty()) {
write_object_field(f, pretty, 0, &mut first, "trace", |f| {
report::write_trace_object(f, pretty, 1, report, options)
})?;
}
#[cfg(not(feature = "trace"))]
if options.show_trace_section && options.show_empty_sections {
write_object_field(f, pretty, 0, &mut first, "trace", |f| f.write_str("{}"))?;
}
if options.show_context_section && (options.show_empty_sections || section_flags.has_context) {
write_object_field(f, pretty, 0, &mut first, "context", |f| {
attachment::write_context_object(f, pretty, 1, report)
})?;
}
if options.show_context_section && (options.show_empty_sections || section_flags.has_system) {
write_object_field(f, pretty, 0, &mut first, "system", |f| {
attachment::write_system_object(f, pretty, 1, report)
})?;
}
if options.show_attachments_section
&& (options.show_empty_sections || section_flags.has_attachments)
{
write_object_field(f, pretty, 0, &mut first, "attachments", |f| {
attachment::write_attachments_array(f, pretty, 1, report)
})?;
}
if pretty && !first {
f.write_char('\n')?;
write_indent(f, 0)?;
}
f.write_char('}')
}
struct JsonSectionFlags {
has_metadata: bool,
has_context: bool,
has_system: bool,
has_attachments: bool,
has_diag_bag: bool,
}
fn calc_section_flags<E, State>(report: &Report<E, State>) -> JsonSectionFlags
where
E: Error,
State: SeverityState,
{
let metadata = report.metadata();
let has_metadata = metadata.error_code().is_some()
|| report.severity().is_some()
|| metadata.category().is_some()
|| metadata.retryable().is_some();
let has_context = !report.context().is_empty();
let has_system = !report.system().is_empty();
let has_attachments = !report.attachments().is_empty();
let has_diag_bag = has_stack_trace(report)
|| has_display_causes(report)
|| has_origin_source_errors(report)
|| has_diag_source_errors(report);
JsonSectionFlags {
has_metadata,
has_context,
has_system,
has_attachments,
has_diag_bag,
}
}
fn has_stack_trace<E, State>(report: &Report<E, State>) -> bool
where
E: Error,
State: SeverityState,
{
report.stack_trace().is_some()
}
fn has_display_causes<E, State>(report: &Report<E, State>) -> bool
where
E: Error,
State: SeverityState,
{
report.display_causes_chain().is_some()
}
fn has_origin_source_errors<E, State>(report: &Report<E, State>) -> bool
where
E: Error,
State: SeverityState,
{
report.origin_src_err_chain().is_some() || report.inner().source().is_some()
}
fn has_diag_source_errors<E, State>(report: &Report<E, State>) -> bool
where
E: Error,
State: SeverityState,
{
report.diag_src_err_chain().is_some()
}