(Bug 1635487) Wired up sync logging for extension pref storage r=lina,markh

Differential Revision: https://phabricator.services.mozilla.com/D80975
This commit is contained in:
lougeniac64 2020-06-27 06:26:22 +00:00
parent 6ff329ef81
commit bce2c33963
28 changed files with 318 additions and 66 deletions

14
Cargo.lock generated
View File

@ -27,6 +27,18 @@ version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2494382e9ba43995f3c56359e518641f450f5c36feeb4632a75cde2ec297c867"
[[package]]
name = "app_services_logger"
version = "0.1.0"
dependencies = [
"golden_gate",
"log",
"nserror",
"nsstring",
"once_cell",
"xpcom",
]
[[package]]
name = "app_units"
version = "0.7.0"
@ -1612,6 +1624,7 @@ dependencies = [
name = "gecko_logger"
version = "0.1.0"
dependencies = [
"app_services_logger",
"env_logger",
"lazy_static",
"log",
@ -1852,6 +1865,7 @@ dependencies = [
name = "gkrust-shared"
version = "0.1.0"
dependencies = [
"app_services_logger",
"audio_thread_priority",
"audioipc-client",
"audioipc-server",

View File

@ -1268,10 +1268,7 @@ impl CertStorage {
NS_OK
}
unsafe fn GetRemainingOperationCount(
&self,
state: *mut i32,
) -> nserror::nsresult {
unsafe fn GetRemainingOperationCount(&self, state: *mut i32) -> nserror::nsresult {
if !is_main_thread() {
return NS_ERROR_NOT_SAME_THREAD;
}

View File

@ -0,0 +1,38 @@
/* 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 http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_services_AppServicesLoggerComponents_h_
#define mozilla_services_AppServicesLoggerComponents_h_
#include "mozIAppServicesLogger.h"
#include "nsCOMPtr.h"
extern "C" {
// Implemented in Rust, in the `app_services_logger` crate.
nsresult NS_NewAppServicesLogger(mozIAppServicesLogger** aResult);
} // extern "C"
namespace mozilla {
namespace appservices {
// The C++ constructor for a `services.appServicesLogger` service. This wrapper
// exists because `components.conf` requires a component class constructor to
// return an `already_AddRefed<T>`, but Rust doesn't have such a type. So we
// call the Rust constructor using a `nsCOMPtr` (which is compatible with Rust's
// `xpcom::RefPtr`) out param, and return that.
already_AddRefed<mozIAppServicesLogger> NewLogService() {
nsCOMPtr<mozIAppServicesLogger> logger;
nsresult rv = NS_NewAppServicesLogger(getter_AddRefs(logger));
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
return logger.forget();
}
} // namespace appservices
} // namespace mozilla
#endif // mozilla_services_AppServicesLoggerComponents_h_

View File

@ -0,0 +1,15 @@
[package]
name = "app_services_logger"
version = "0.1.0"
authors = ["lougeniac64 <lougeniaC64@users.noreply.github.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
golden_gate = { path = "../../../services/sync/golden_gate" }
log = "0.4"
once_cell = "1.4.0"
nserror = { path = "../../../xpcom/rust/nserror" }
nsstring = { path = "../../../xpcom/rust/nsstring" }
xpcom = { path = "../../../xpcom/rust/xpcom" }

View File

@ -0,0 +1,15 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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 http://mozilla.org/MPL/2.0/.
Classes = [
{
'cid': '{d2716568-f5fa-4989-91dd-e11599e932a1}',
'contract_ids': ['@mozilla.org/appservices/logger;1'],
'type': 'mozIAppServicesLogger',
'headers': ['mozilla/appservices/AppServicesLoggerComponents.h'],
'constructor': 'mozilla::appservices::NewLogService',
},
]

View File

@ -0,0 +1,71 @@
/* 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/. */
//! This provides a XPCOM service to send app services logs to the desktop
#[macro_use]
extern crate xpcom;
use golden_gate::log::LogSink;
use log;
use nserror::{nsresult, NS_OK};
use nsstring::nsAString;
use once_cell::sync::Lazy;
use std::{cmp, collections::HashMap, sync::RwLock};
use xpcom::{
interfaces::{mozIAppServicesLogger, mozIServicesLogSink},
RefPtr,
};
#[derive(xpcom)]
#[xpimplements(mozIAppServicesLogger)]
#[refcnt = "nonatomic"]
pub struct InitAppServicesLogger {}
pub static LOGGERS_BY_TARGET: Lazy<RwLock<HashMap<String, LogSink>>> = Lazy::new(|| {
let h: HashMap<String, LogSink> = HashMap::new();
let m = RwLock::new(h);
m
});
impl AppServicesLogger {
xpcom_method!(register => Register(target: *const nsAString, logger: *const mozIServicesLogSink));
fn register(&self, target: &nsAString, logger: &mozIServicesLogSink) -> Result<(), nsresult> {
let log_sink_logger = LogSink::with_logger(Some(logger))?;
let max_level = cmp::max(log::max_level(), log_sink_logger.max_level);
// Note: This will only work if the max_level is lower than the compile-time
// max_level_* filter.
log::set_max_level(max_level);
LOGGERS_BY_TARGET
.write()
.unwrap()
.insert(target.to_string(), log_sink_logger);
Ok(())
}
pub fn is_app_services_logger_registered(target: String) -> bool {
match LOGGERS_BY_TARGET.read() {
Ok(loggers_by_target) => loggers_by_target.contains_key(&target),
Err(_e) => false,
}
}
}
/// The constructor for an `AppServicesLogger` service. This uses C linkage so that it
/// can be called from C++. See `AppServicesLoggerComponents.h` for the C++
/// constructor that's passed to the component manager.
///
/// # Safety
///
/// This function is unsafe because it dereferences `result`.
#[no_mangle]
pub unsafe extern "C" fn NS_NewAppServicesLogger(
result: *mut *const mozIAppServicesLogger,
) -> nsresult {
let logger = AppServicesLogger::allocate(InitAppServicesLogger {});
RefPtr::new(logger.coerce::<mozIAppServicesLogger>()).forget(&mut *result);
NS_OK
}

View File

@ -9,6 +9,10 @@ with Files('**'):
TEST_DIRS += ['tests']
EXPORTS.mozilla.appservices += [
'app_services_logger/AppServicesLoggerComponents.h',
]
EXTRA_COMPONENTS += [
'servicesComponents.manifest',
]
@ -37,3 +41,7 @@ TESTING_JS_MODULES.services.common += [
]
SPHINX_TREES['services'] = 'docs'
XPCOM_MANIFESTS += [
'app_services_logger/components.conf',
]

View File

@ -12,7 +12,8 @@ with Files('**'):
XPIDL_MODULE = 'services'
XPIDL_SOURCES += [
'mozIAppServicesLogger.idl',
'mozIBridgedSyncEngine.idl',
'mozIInterruptible.idl',
'mozIServicesLogger.idl',
'mozIServicesLogSink.idl',
]

View File

@ -0,0 +1,11 @@
/* 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 http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
#include "mozIServicesLogSink.idl"
[scriptable, uuid(446dd837-fbb0-41e4-8221-f740f672b20d)]
interface mozIAppServicesLogger : nsISupports {
void register(in AString target, in mozIServicesLogSink logger);
};

View File

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozIServicesLogger.idl"
#include "mozIServicesLogSink.idl"
#include "nsISupports.idl"
interface nsIVariant;
@ -63,7 +63,7 @@ interface mozIBridgedSyncEngine : nsISupports {
// Wires up the Sync logging machinery to the bridged engine. This can be
// `null`, in which case any logs from the engine will be discarded.
attribute mozIServicesLogger logger;
attribute mozIServicesLogSink logger;
// Returns the last sync time, in milliseconds, for this engine's
// collection. This is used to build the collection URL for fetching

View File

@ -8,12 +8,13 @@
// The synced bookmarks mirror and bridged engines implement this interface
// to hook in to the services `LogManager` infrastructure.
[scriptable, uuid(c92bfe0d-50b7-4a7f-9686-fe5335a696b9)]
interface mozIServicesLogger : nsISupports {
interface mozIServicesLogSink : nsISupports {
const short LEVEL_OFF = 0;
const short LEVEL_ERROR = 1;
const short LEVEL_WARN = 2;
const short LEVEL_DEBUG = 3;
const short LEVEL_TRACE = 4;
const short LEVEL_INFO = 3;
const short LEVEL_DEBUG = 4;
const short LEVEL_TRACE = 5;
attribute short maxLevel;
@ -21,4 +22,5 @@ interface mozIServicesLogger : nsISupports {
void warn(in AString message);
void debug(in AString message);
void trace(in AString message);
void info(in AString message);
};

View File

@ -8,11 +8,11 @@ use log::{Level, LevelFilter, Log, Metadata, Record};
use moz_task::{Task, TaskRunnable, ThreadPtrHandle, ThreadPtrHolder};
use nserror::nsresult;
use nsstring::nsString;
use xpcom::{interfaces::mozIServicesLogger, RefPtr};
use xpcom::{interfaces::mozIServicesLogSink, RefPtr};
pub struct LogSink {
pub max_level: LevelFilter,
logger: Option<ThreadPtrHandle<mozIServicesLogger>>,
logger: Option<ThreadPtrHandle<mozIServicesLogSink>>,
}
impl Default for LogSink {
@ -32,7 +32,7 @@ impl LogSink {
/// these, but, for now, we've just duplicated it to make prototyping
/// easier.
#[inline]
pub fn new(max_level: LevelFilter, logger: ThreadPtrHandle<mozIServicesLogger>) -> LogSink {
pub fn new(max_level: LevelFilter, logger: ThreadPtrHandle<mozIServicesLogSink>) -> LogSink {
LogSink {
max_level,
logger: Some(logger),
@ -43,7 +43,7 @@ impl LogSink {
/// underlying implementation. The `logger` will always be called
/// asynchronously on its owning thread; it doesn't need to be
/// thread-safe.
pub fn with_logger(logger: Option<&mozIServicesLogger>) -> Result<LogSink, nsresult> {
pub fn with_logger(logger: Option<&mozIServicesLogSink>) -> Result<LogSink, nsresult> {
Ok(if let Some(logger) = logger {
// Fetch the maximum log level while we're on the main thread, so
// that `LogSink::enabled()` can check it while on the background
@ -54,10 +54,11 @@ impl LogSink {
let rv = unsafe { logger.GetMaxLevel(&mut raw_max_level) };
let max_level = if rv.succeeded() {
match raw_max_level as i64 {
mozIServicesLogger::LEVEL_ERROR => LevelFilter::Error,
mozIServicesLogger::LEVEL_WARN => LevelFilter::Warn,
mozIServicesLogger::LEVEL_DEBUG => LevelFilter::Debug,
mozIServicesLogger::LEVEL_TRACE => LevelFilter::Trace,
mozIServicesLogSink::LEVEL_ERROR => LevelFilter::Error,
mozIServicesLogSink::LEVEL_WARN => LevelFilter::Warn,
mozIServicesLogSink::LEVEL_DEBUG => LevelFilter::Debug,
mozIServicesLogSink::LEVEL_TRACE => LevelFilter::Trace,
mozIServicesLogSink::LEVEL_INFO => LevelFilter::Info,
_ => LevelFilter::Off,
}
} else {
@ -65,15 +66,15 @@ impl LogSink {
};
LogSink::new(
max_level,
ThreadPtrHolder::new(cstr!("mozIServicesLogger"), RefPtr::new(logger))?,
ThreadPtrHolder::new(cstr!("mozIServicesLogSink"), RefPtr::new(logger))?,
)
} else {
LogSink::default()
})
}
/// Returns a reference to the underlying `mozIServicesLogger`.
pub fn logger(&self) -> Option<&mozIServicesLogger> {
/// Returns a reference to the underlying `mozIServicesLogSink`.
pub fn logger(&self) -> Option<&mozIServicesLogSink> {
self.logger.as_ref().and_then(|l| l.get())
}
@ -131,7 +132,7 @@ impl Log for LogSink {
/// Logs a message to the mirror logger. This task is created on the background
/// thread queue, and dispatched to the main thread.
struct LogTask {
logger: ThreadPtrHandle<mozIServicesLogger>,
logger: ThreadPtrHandle<mozIServicesLogSink>,
level: Level,
message: nsString,
}
@ -152,7 +153,9 @@ impl Task for LogTask {
Level::Trace => unsafe {
logger.Trace(&*self.message);
},
_ => {}
Level::Info => unsafe {
logger.Info(&*self.message);
},
}
}

View File

@ -30,7 +30,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
});
var EXPORTED_SYMBOLS = ["BridgedEngine"];
var EXPORTED_SYMBOLS = ["BridgedEngine", "LogAdapter"];
/**
* A stub store that converts between raw decrypted incoming records and
@ -151,7 +151,7 @@ class InterruptedError extends Error {
}
/**
* Adapts a `Log.jsm` logger to a `mozIServicesLogger`. This class is copied
* Adapts a `Log.jsm` logger to a `mozIServicesLogSink`. This class is copied
* from `SyncedBookmarksMirror.jsm`.
*/
class LogAdapter {
@ -162,18 +162,18 @@ class LogAdapter {
get maxLevel() {
let level = this.log.level;
if (level <= Log.Level.All) {
return Ci.mozIServicesLogger.LEVEL_TRACE;
return Ci.mozIServicesLogSink.LEVEL_TRACE;
}
if (level <= Log.Level.Info) {
return Ci.mozIServicesLogger.LEVEL_DEBUG;
return Ci.mozIServicesLogSink.LEVEL_DEBUG;
}
if (level <= Log.Level.Warn) {
return Ci.mozIServicesLogger.LEVEL_WARN;
return Ci.mozIServicesLogSink.LEVEL_WARN;
}
if (level <= Log.Level.Error) {
return Ci.mozIServicesLogger.LEVEL_ERROR;
return Ci.mozIServicesLogSink.LEVEL_ERROR;
}
return Ci.mozIServicesLogger.LEVEL_OFF;
return Ci.mozIServicesLogSink.LEVEL_OFF;
}
trace(message) {
@ -214,7 +214,6 @@ function BridgedEngine(bridge, name, service) {
SyncEngine.call(this, name, service);
this._bridge = bridge;
this._bridge.logger = new LogAdapter(this._log);
}
BridgedEngine.prototype = {

View File

@ -15,6 +15,7 @@ const { XPCOMUtils } = ChromeUtils.import(
XPCOMUtils.defineLazyModuleGetters(this, {
BridgedEngine: "resource://services-sync/bridged_engine.js",
LogAdapter: "resource://services-sync/bridged_engine.js",
extensionStorageSync: "resource://gre/modules/ExtensionStorageSync.jsm",
Observers: "resource://services-common/observers.js",
Svc: "resource://services-sync/util.js",
@ -73,6 +74,12 @@ function setEngineEnabled(enabled) {
function ExtensionStorageEngineBridge(service) {
let bridge = StorageSyncService.getInterface(Ci.mozIBridgedSyncEngine);
BridgedEngine.call(this, bridge, "Extension-Storage", service);
let app_services_logger = Cc["@mozilla.org/appservices/logger;1"].getService(
Ci.mozIAppServicesLogger
);
let logger_target = "app-services:webext_storage:sync";
app_services_logger.register(logger_target, new LogAdapter(this._log));
}
ExtensionStorageEngineBridge.prototype = {

View File

@ -21,7 +21,7 @@ use webext_storage::STORAGE_VERSION;
use xpcom::{
interfaces::{
mozIBridgedSyncEngineApplyCallback, mozIBridgedSyncEngineCallback,
mozIExtensionStorageCallback, mozIServicesLogger, nsIFile, nsISerialEventTarget,
mozIExtensionStorageCallback, mozIServicesLogSink, nsIFile, nsISerialEventTarget,
},
RefPtr,
};
@ -311,13 +311,13 @@ impl StorageSyncArea {
/// `mozIBridgedSyncEngine` implementation.
impl StorageSyncArea {
xpcom_method!(get_logger => GetLogger() -> *const mozIServicesLogger);
fn get_logger(&self) -> Result<RefPtr<mozIServicesLogger>> {
xpcom_method!(get_logger => GetLogger() -> *const mozIServicesLogSink);
fn get_logger(&self) -> Result<RefPtr<mozIServicesLogSink>> {
Err(NS_OK)?
}
xpcom_method!(set_logger => SetLogger(logger: *const mozIServicesLogger));
fn set_logger(&self, _logger: Option<&mozIServicesLogger>) -> Result<()> {
xpcom_method!(set_logger => SetLogger(logger: *const mozIServicesLogSink));
fn set_logger(&self, _logger: Option<&mozIServicesLogSink>) -> Result<()> {
Ok(())
}

View File

@ -88,7 +88,7 @@ const DEFAULT_MAX_FRECENCIES_TO_RECALCULATE = 400;
// Use a shared jankYielder in these functions
XPCOMUtils.defineLazyGetter(this, "yieldState", () => Async.yieldState());
/** Adapts a `Log.jsm` logger to a `mozIServicesLogger`. */
/** Adapts a `Log.jsm` logger to a `mozIServicesLogSink`. */
class LogAdapter {
constructor(log) {
this.log = log;
@ -97,18 +97,18 @@ class LogAdapter {
get maxLevel() {
let level = this.log.level;
if (level <= Log.Level.All) {
return Ci.mozIServicesLogger.LEVEL_TRACE;
return Ci.mozIServicesLogSink.LEVEL_TRACE;
}
if (level <= Log.Level.Info) {
return Ci.mozIServicesLogger.LEVEL_DEBUG;
return Ci.mozIServicesLogSink.LEVEL_DEBUG;
}
if (level <= Log.Level.Warn) {
return Ci.mozIServicesLogger.LEVEL_WARN;
return Ci.mozIServicesLogSink.LEVEL_WARN;
}
if (level <= Log.Level.Error) {
return Ci.mozIServicesLogger.LEVEL_ERROR;
return Ci.mozIServicesLogSink.LEVEL_ERROR;
}
return Ci.mozIServicesLogger.LEVEL_OFF;
return Ci.mozIServicesLogSink.LEVEL_OFF;
}
trace(message) {

View File

@ -14,7 +14,7 @@ use moz_task::{Task, TaskRunnable, ThreadPtrHandle};
use nserror::nsresult;
use nsstring::{nsACString, nsCString, nsString};
use storage_variant::HashPropertyBag;
use xpcom::interfaces::{mozIServicesLogger, mozISyncedBookmarksMirrorProgressListener};
use xpcom::interfaces::{mozIServicesLogSink, mozISyncedBookmarksMirrorProgressListener};
extern "C" {
fn NS_GeneratePlacesGUID(guid: *mut nsACString) -> nsresult;
@ -107,14 +107,14 @@ impl dogear::Driver for Driver {
pub struct Logger {
pub max_level: LevelFilter,
logger: Option<ThreadPtrHandle<mozIServicesLogger>>,
logger: Option<ThreadPtrHandle<mozIServicesLogSink>>,
}
impl Logger {
#[inline]
pub fn new(
max_level: LevelFilter,
logger: Option<ThreadPtrHandle<mozIServicesLogger>>,
logger: Option<ThreadPtrHandle<mozIServicesLogSink>>,
) -> Logger {
Logger { max_level, logger }
}
@ -153,7 +153,7 @@ impl Log for Logger {
/// Logs a message to the mirror logger. This task is created on the async
/// thread, and dispatched to the main thread.
struct LogTask {
logger: ThreadPtrHandle<mozIServicesLogger>,
logger: ThreadPtrHandle<mozIServicesLogSink>,
level: Level,
message: nsString,
}

View File

@ -14,7 +14,7 @@ use storage::Conn;
use thin_vec::ThinVec;
use xpcom::{
interfaces::{
mozIPlacesPendingOperation, mozIServicesLogger, mozIStorageConnection,
mozIPlacesPendingOperation, mozIServicesLogSink, mozIStorageConnection,
mozISyncedBookmarksMirrorCallback, mozISyncedBookmarksMirrorProgressListener,
},
RefPtr, XpCom,
@ -29,7 +29,7 @@ use crate::store;
#[refcnt = "nonatomic"]
pub struct InitSyncedBookmarksMerger {
db: RefCell<Option<Conn>>,
logger: RefCell<Option<RefPtr<mozIServicesLogger>>>,
logger: RefCell<Option<RefPtr<mozIServicesLogSink>>>,
}
impl SyncedBookmarksMerger {
@ -56,16 +56,16 @@ impl SyncedBookmarksMerger {
Ok(())
}
xpcom_method!(get_logger => GetLogger() -> *const mozIServicesLogger);
fn get_logger(&self) -> Result<RefPtr<mozIServicesLogger>, nsresult> {
xpcom_method!(get_logger => GetLogger() -> *const mozIServicesLogSink);
fn get_logger(&self) -> Result<RefPtr<mozIServicesLogSink>, nsresult> {
match *self.logger.borrow() {
Some(ref logger) => Ok(logger.clone()),
None => Err(NS_OK),
}
}
xpcom_method!(set_logger => SetLogger(logger: *const mozIServicesLogger));
fn set_logger(&self, logger: Option<&mozIServicesLogger>) -> Result<(), nsresult> {
xpcom_method!(set_logger => SetLogger(logger: *const mozIServicesLogSink));
fn set_logger(&self, logger: Option<&mozIServicesLogSink>) -> Result<(), nsresult> {
self.logger.replace(logger.map(RefPtr::new));
Ok(())
}
@ -125,7 +125,7 @@ struct MergeTask {
db: Conn,
controller: Arc<AbortController>,
max_log_level: LevelFilter,
logger: Option<ThreadPtrHandle<mozIServicesLogger>>,
logger: Option<ThreadPtrHandle<mozIServicesLogSink>>,
local_time_millis: i64,
remote_time_millis: i64,
weak_uploads: Vec<nsString>,
@ -138,7 +138,7 @@ impl MergeTask {
fn new(
db: &Conn,
controller: Arc<AbortController>,
logger: Option<RefPtr<mozIServicesLogger>>,
logger: Option<RefPtr<mozIServicesLogSink>>,
local_time_seconds: i64,
remote_time_seconds: i64,
weak_uploads: Vec<nsString>,
@ -152,15 +152,15 @@ impl MergeTask {
Some(level)
})
.map(|level| match level as i64 {
mozIServicesLogger::LEVEL_ERROR => LevelFilter::Error,
mozIServicesLogger::LEVEL_WARN => LevelFilter::Warn,
mozIServicesLogger::LEVEL_DEBUG => LevelFilter::Debug,
mozIServicesLogger::LEVEL_TRACE => LevelFilter::Trace,
mozIServicesLogSink::LEVEL_ERROR => LevelFilter::Error,
mozIServicesLogSink::LEVEL_WARN => LevelFilter::Warn,
mozIServicesLogSink::LEVEL_DEBUG => LevelFilter::Debug,
mozIServicesLogSink::LEVEL_TRACE => LevelFilter::Trace,
_ => LevelFilter::Off,
})
.unwrap_or(LevelFilter::Off);
let logger = match logger {
Some(logger) => Some(ThreadPtrHolder::new(cstr!("mozIServicesLogger"), logger)?),
Some(logger) => Some(ThreadPtrHolder::new(cstr!("mozIServicesLogSink"), logger)?),
None => None,
};
let progress = callback

View File

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozIServicesLogger.idl"
#include "mozIServicesLogSink.idl"
#include "nsISupports.idl"
interface mozIPlacesPendingOperation;
@ -79,7 +79,7 @@ interface mozISyncedBookmarksMerger : nsISupports {
attribute mozIStorageConnection db;
// Optional; used for logging.
attribute mozIServicesLogger logger;
attribute mozIServicesLogSink logger;
// Merges the local and remote bookmark trees, applies the merged tree to
// Places, and stages locally changed and reconciled items for upload. When

View File

@ -49,6 +49,7 @@ wgpu_bindings = { path = "../../../../gfx/wgpu_bindings", optional = true }
mapped_hyph = { git = "https://github.com/jfkthame/mapped_hyph.git", tag = "v0.3.0" }
remote = { path = "../../../../remote", optional = true }
fog = { path = "../../../components/glean", optional = true }
app_services_logger = { path = "../../../../services/common/app_services_logger" }
unic-langid = { version = "0.8", features = ["likelysubtags"] }
unic-langid-ffi = { path = "../../../../intl/locale/rust/unic-langid-ffi" }

View File

@ -6,6 +6,7 @@
extern crate geckoservo;
extern crate app_services_logger;
#[cfg(feature = "cubeb-remoting")]
extern crate audioipc_client;
#[cfg(feature = "cubeb-remoting")]
@ -82,8 +83,10 @@ extern crate remote;
extern crate gecko_logger;
use std::ffi::CStr;
use std::os::raw::c_char;
extern crate log;
use log::info;
use std::{ffi::CStr, os::raw::c_char};
use gecko_logger::GeckoLogger;
@ -102,6 +105,15 @@ pub extern "C" fn intentional_panic(message: *const c_char) {
panic!("{}", unsafe { CStr::from_ptr(message) }.to_string_lossy());
}
/// Used to implement `nsIDebug2::rustLog` for testing purposes.
#[no_mangle]
pub extern "C" fn debug_log(target: *const c_char, message: *const c_char) {
unsafe {
// NOTE: The `info!` log macro is used here because we have the `release_max_level_info` feature set.
info!(target: CStr::from_ptr(target).to_str().unwrap(), "{}", CStr::from_ptr(message).to_str().unwrap());
}
}
#[cfg(feature = "oom_with_hook")]
mod oom_hook {
use std::alloc::{set_alloc_error_hook, Layout};

View File

@ -0,0 +1,26 @@
let waitForDebugLog = target =>
new Promise(resolve => {
Cc["@mozilla.org/appservices/logger;1"]
.getService(Ci.mozIAppServicesLogger)
.register(target, {
maxLevel: Ci.mozIServicesLogSink.LEVEL_INFO,
info: resolve,
});
});
let rustLog = (target, message) => {
Cc["@mozilla.org/xpcom/debug;1"]
.getService(Ci.nsIDebug2)
.rustLog(target, message);
};
add_task(async () => {
let target = "app-services:webext_storage:sync";
let expectedMessage = "info error: uh oh";
let promiseMessage = waitForDebugLog(target);
rustLog(target, expectedMessage);
let actualMessage = await promiseMessage;
Assert.ok(actualMessage.includes(expectedMessage));
});

View File

@ -44,3 +44,4 @@ skip-if = devedition
[test_ignore_legacy_directory.js]
[test_select_profile_argument.js]
[test_select_profile_argument_new.js]
[test_register_app_services_logger.js]

View File

@ -150,6 +150,15 @@ nsDebugImpl::RustPanic(const char* aMessage) {
return NS_OK;
}
// From toolkit/library/rust/lib.rs
extern "C" void debug_log(const char* target, const char* message);
NS_IMETHODIMP
nsDebugImpl::RustLog(const char* aTarget, const char* aMessage) {
debug_log(aTarget, aMessage);
return NS_OK;
}
NS_IMETHODIMP
nsDebugImpl::GetIsDebugBuild(bool* aResult) {
#ifdef DEBUG

View File

@ -87,6 +87,15 @@ interface nsIDebug2 : nsISupports
*/
void rustPanic(in string aMessage);
/**
* Request the process to log a message for a target and level from Rust code.
*
* @param aTarget the string representing the log target.
* @param aMessage the string representing the log message.
*/
void rustLog(in string aTarget,
in string aMessage);
/**
* Cause an Out of Memory Crash.
*/

View File

@ -9,3 +9,4 @@ license = "MPL-2.0"
lazy_static = "1"
log = {version = "0.4", features = ["release_max_level_info"]}
env_logger = {version = "0.6", default-features = false} # disable `regex` to reduce code size
app_services_logger = { path = "../../../services/common/app_services_logger" }

View File

@ -7,7 +7,7 @@
#[macro_use]
extern crate lazy_static;
#[cfg(not(target_os = "android"))]
use app_services_logger::{AppServicesLogger, LOGGERS_BY_TARGET};
use log::Log;
use log::{Level, LevelFilter};
use std::boxed::Box;
@ -185,6 +185,18 @@ impl GeckoLogger {
log::set_boxed_logger(Box::new(gecko_logger))
}
fn should_log_to_app_services(target: &str) -> bool {
return AppServicesLogger::is_app_services_logger_registered(target.into());
}
fn maybe_log_to_app_services(&self, record: &log::Record) {
if Self::should_log_to_app_services(record.target()) {
if let Some(l) = LOGGERS_BY_TARGET.read().unwrap().get(record.target()) {
l.log(record);
}
}
}
fn should_log_to_gfx_critical_note(record: &log::Record) -> bool {
record.level() == log::Level::Error && record.target().contains("webrender")
}
@ -232,12 +244,13 @@ impl GeckoLogger {
impl log::Log for GeckoLogger {
fn enabled(&self, metadata: &log::Metadata) -> bool {
self.logger.enabled(metadata)
self.logger.enabled(metadata) || GeckoLogger::should_log_to_app_services(metadata.target())
}
fn log(&self, record: &log::Record) {
// Forward log to gfxCriticalNote, if the log should be in gfx crash log.
self.maybe_log_to_gfx_critical_note(record);
self.maybe_log_to_app_services(record);
self.log_out(record);
}

View File

@ -216,7 +216,6 @@ impl TaskRunnable {
.compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
{
Ok(_) => {
assert!(!is_current_thread(&self.original_thread));
self.task.run();
Self::dispatch(RefPtr::new(self), &self.original_thread)
}