// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/.
use std::fmt; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc;
/// Stores information about a ping. /// /// This is required so that given metric data queued on disk we can send /// pings with the correct settings, e.g. whether it has a client_id. #[derive(Clone)] pubstruct PingType(Arc<InnerPing>);
struct InnerPing { /// The name of the ping. pub name: String, /// Whether the ping should include the client ID. pub include_client_id: bool, /// Whether the ping should be sent if it is empty pub send_if_empty: bool, /// Whether to use millisecond-precise start/end times. pub precise_timestamps: bool, /// Whether to include the {client|ping}_info sections on assembly. pub include_info_sections: bool, /// Whether this ping is enabled. pub enabled: AtomicBool, /// Other pings that should be scheduled when this ping is sent. pub schedules_pings: Vec<String>, /// The "reason" codes that this ping can send pub reason_codes: Vec<String>,
/// True when it follows the `collection_enabled` flag (aka `upload_enabled`) flag. /// Otherwise it needs to be enabled through `enabled_pings`.
follows_collection_enabled: AtomicBool,
}
// IMPORTANT: // // When changing this implementation, make sure all the operations are // also declared in the related trait in `../traits/`. impl PingType { /// Creates a new ping type for the given name, whether to include the client ID and whether to /// send this ping empty. /// /// # Arguments /// /// * `name` - The name of the ping. /// * `include_client_id` - Whether to include the client ID in the assembled ping when submitting. /// * `send_if_empty` - Whether the ping should be sent empty or not. /// * `precise_timestamps` - Whether the ping should use precise timestamps for the start and end time. /// * `include_info_sections` - Whether the ping should include the client/ping_info sections. /// * `enabled` - Whether or not this ping is enabled. Note: Data that would be sent on a disabled /// ping will still be collected but is discarded rather than being submitted. /// * `reason_codes` - The valid reason codes for this ping. #[allow(clippy::too_many_arguments)] pubfn new<A: Into<String>>(
name: A,
include_client_id: bool,
send_if_empty: bool,
precise_timestamps: bool,
include_info_sections: bool,
enabled: bool,
schedules_pings: Vec<String>,
reason_codes: Vec<String>,
follows_collection_enabled: bool,
) -> Self { Self::new_internal(
name,
include_client_id,
send_if_empty,
precise_timestamps,
include_info_sections,
enabled,
schedules_pings,
reason_codes,
follows_collection_enabled,
)
}
/// Enable or disable a ping. /// /// Disabling a ping causes all data for that ping to be removed from storage /// and all pending pings of that type to be deleted. pubfn set_enabled(&self, enabled: bool) { crate::set_ping_enabled(self, enabled)
}
/// Store whether this ping is enabled or not. /// /// **Note**: For internal use only. Only stores the flag. Does not touch any stored data. /// Use the public API `PingType::set_enabled` instead. pub(crate) fn store_enabled(&self, enabled: bool) { self.0.enabled.store(enabled, Ordering::Release);
}
pub(crate) fn enabled(&self, glean: &Glean) -> bool { ifself.0.follows_collection_enabled.load(Ordering::Relaxed) { // if this follows collection_enabled: // 1. check that first. if disabled, we're done // 2. if enabled, check server-knobs // 3. If that is not set, fall-through checking the ping if !glean.is_upload_enabled() { returnfalse;
}
let remote_settings_config = &glean.remote_settings_config.lock().unwrap();
/// Submits the ping for eventual uploading. /// /// The ping content is assembled as soon as possible, but upload is not /// guaranteed to happen immediately, as that depends on the upload policies. /// /// If the ping currently contains no content, it will not be sent, /// unless it is configured to be sent if empty. /// /// # Arguments /// /// * `reason` - the reason the ping was triggered. Included in the /// `ping_info.reason` part of the payload. pubfn submit(&self, reason: Option<String>) { let ping = PingType(Arc::clone(&self.0));
// Need to separate access to the Glean object from access to global state. // `trigger_upload` itself might lock the Glean object and we need to avoid that deadlock. crate::dispatcher::launch(|| { let sent = crate::core::with_glean(move |glean| ping.submit_sync(glean, reason.as_deref())); if sent { let state = crate::global_state().lock().unwrap(); iflet Err(e) = state.callbacks.trigger_upload() {
log::error!("Triggering upload failed. Error: {}", e);
}
}
})
}
/// Collects and submits a ping for eventual uploading. /// /// # Returns /// /// Whether the ping was succesfully assembled and queued. #[doc(hidden)] pubfn submit_sync(&self, glean: &Glean, reason: Option<&str>) -> bool { if !self.enabled(glean) {
log::info!( "The ping '{}' is disabled and will be discarded and not submitted", self.0.name
);
returnfalse;
}
let ping = &self.0;
// Allowing `clippy::manual_filter`. // This causes a false positive. // We have a side-effect in the `else` branch, // so shouldn't delete it. #[allow(unknown_lints)] #[allow(clippy::manual_filter)] let corrected_reason = match reason {
Some(reason) => { if ping.reason_codes.contains(&reason.to_string()) {
Some(reason)
} else {
log::error!("Invalid reason code {} for ping {}", reason, ping.name);
None
}
}
None => None,
};
let ping_maker = PingMaker::new(); let doc_id = Uuid::new_v4().to_string(); let url_path = glean.make_path(&ping.name, &doc_id); match ping_maker.collect(glean, self, corrected_reason, &doc_id, &url_path) {
None => {
log::info!( "No content for ping '{}', therefore no ping queued.",
ping.name
); false
}
Some(ping) => { if !self.enabled(glean) {
log::info!( "The ping '{}' is disabled and will be discarded and not submitted",
ping.name
);
returnfalse;
}
// This metric is recorded *after* the ping is collected (since // that is the only way to know *if* it will be submitted). The // implication of this is that the count for a metrics ping will // be included in the *next* metrics ping.
glean
.additional_metrics
.pings_submitted
.get(ping.name)
.add_sync(glean, 1);
iflet Err(e) = ping_maker.store_ping(glean.get_data_path(), &ping) {
log::warn!( "IO error while writing ping to file: {}. Enqueuing upload of what we have in memory.",
e
);
glean.additional_metrics.io_errors.add_sync(glean, 1); // `serde_json::to_string` only fails if serialization of the content // fails or it contains maps with non-string keys. // However `ping.content` is already a `JsonValue`, // so both scenarios should be impossible. let content =
::serde_json::to_string(&ping.content).expect("ping serialization failed"); // TODO: Shouldn't we consolidate on a single collected Ping representation? let ping = PingPayload {
document_id: ping.doc_id.to_string(),
upload_path: ping.url_path.to_string(),
json_body: content,
headers: Some(ping.headers),
body_has_info_sections: self.0.include_info_sections,
ping_name: self.0.name.to_string(),
};
log::info!( "The ping '{}' was submitted and will be sent as soon as possible",
ping.name
);
if ping.schedules_pings.is_empty() { let ping_schedule = glean
.ping_schedule
.get(ping.name)
.map(|v| &v[..])
.unwrap_or(&[]);
if !ping_schedule.is_empty() {
log::info!( "The ping '{}' is being used to schedule other pings: {:?}",
ping.name,
ping_schedule
);
for scheduled_ping_name in ping_schedule {
glean.submit_ping_by_name(scheduled_ping_name, reason);
}
}
} else {
log::info!( "The ping '{}' is being used to schedule other pings: {:?}",
ping.name,
ping.schedules_pings
); for scheduled_ping_name in &ping.schedules_pings {
glean.submit_ping_by_name(scheduled_ping_name, reason);
}
}
true
}
}
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-06-18)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.