2017-08-28 02:54:12 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
|
|
|
/* 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 DecoderDoctorLogger_h_
|
|
|
|
#define DecoderDoctorLogger_h_
|
|
|
|
|
|
|
|
#include "DDLoggedTypeTraits.h"
|
2017-10-12 08:15:35 +03:00
|
|
|
#include "DDLogCategory.h"
|
2017-08-28 02:54:12 +03:00
|
|
|
#include "DDLogValue.h"
|
|
|
|
#include "mozilla/Atomics.h"
|
|
|
|
#include "mozilla/DefineEnum.h"
|
|
|
|
#include "mozilla/MozPromise.h"
|
|
|
|
#include "nsString.h"
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
// Main class used to capture log messages from the media stack, and to
|
|
|
|
// retrieve processed messages associated with an HTMLMediaElement.
|
|
|
|
//
|
|
|
|
// The logging APIs are designed to work as fast as possible (in most cases
|
|
|
|
// only checking a couple of atomic variables, and not allocating memory), so
|
|
|
|
// as not to introduce perceptible latency.
|
|
|
|
// Consider using DDLOG...() macros, and IsDDLoggingEnabled(), to avoid any
|
|
|
|
// unneeded work when logging is not enabled.
|
|
|
|
//
|
|
|
|
// Structural logging messages are used to determine when objects are created
|
|
|
|
// and destroyed, and to link objects that depend on each other, ultimately
|
|
|
|
// tying groups of objects and their messages to HTMLMediaElement objects.
|
|
|
|
//
|
|
|
|
// A separate thread processes log messages, and can asynchronously retrieve
|
|
|
|
// processed messages that correspond to a given HTMLMediaElement.
|
|
|
|
// That thread is also responsible for removing dated messages, so as not to
|
|
|
|
// take too much memory.
|
|
|
|
class DecoderDoctorLogger
|
|
|
|
{
|
|
|
|
public:
|
2017-12-04 02:52:51 +03:00
|
|
|
// Called by nsLayoutStatics::Initialize() before any other media work.
|
|
|
|
// Pre-enables logging if MOZ_LOG requires DDLogger.
|
|
|
|
static void Init();
|
|
|
|
|
2017-08-28 02:54:12 +03:00
|
|
|
// Is logging currently enabled? This is tested anyway in all public `Log...`
|
|
|
|
// functions, but it may be used to prevent logging-only work in clients.
|
|
|
|
static inline bool IsDDLoggingEnabled()
|
|
|
|
{
|
|
|
|
return MOZ_UNLIKELY(static_cast<LogState>(sLogState) == scEnabled);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Shutdown logging. This will prevent more messages to be queued, but the
|
|
|
|
// already-queued messages may still get processed.
|
|
|
|
static void ShutdownLogging() { sLogState = scShutdown; }
|
|
|
|
|
|
|
|
// Something went horribly wrong, stop all logging and log processing.
|
|
|
|
static void Panic(const char* aReason)
|
|
|
|
{
|
|
|
|
PanicInternal(aReason, /* aDontBlock */ false);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Logging functions.
|
|
|
|
//
|
|
|
|
// All logging functions take:
|
|
|
|
// - The object that produces the message, either as a template type (for
|
|
|
|
// which a specialized DDLoggedTypeTraits exists), or a pointer and a type
|
|
|
|
// name (needed for inner classes that cannot specialize DDLoggedTypeTraits.)
|
2017-10-12 08:15:35 +03:00
|
|
|
// - A DDLogCategory defining the type of log message; some are used
|
2017-08-28 02:54:12 +03:00
|
|
|
// internally for capture the lifetime and linking of C++ objects, others
|
|
|
|
// are used to split messages into different domains.
|
|
|
|
// - A label (string literal).
|
|
|
|
// - An optional Variant value, see DDLogValue for the accepted types.
|
|
|
|
//
|
|
|
|
// The following `EagerLog...` functions always cause their arguments to be
|
|
|
|
// pre-evaluated even if logging is disabled, in which case runtime could be
|
|
|
|
// wasted. Consider using `DDLOG...` macros instead, or test
|
|
|
|
// `IsDDLoggingEnabled()` first.
|
|
|
|
|
|
|
|
template<typename Value>
|
|
|
|
static void EagerLogValue(const char* aSubjectTypeName,
|
|
|
|
const void* aSubjectPointer,
|
2017-10-12 08:15:35 +03:00
|
|
|
DDLogCategory aCategory,
|
2017-08-28 02:54:12 +03:00
|
|
|
const char* aLabel,
|
|
|
|
Value&& aValue)
|
|
|
|
{
|
|
|
|
Log(aSubjectTypeName,
|
|
|
|
aSubjectPointer,
|
2017-10-12 08:15:35 +03:00
|
|
|
aCategory,
|
2017-08-28 02:54:12 +03:00
|
|
|
aLabel,
|
|
|
|
DDLogValue{ Forward<Value>(aValue) });
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Subject, typename Value>
|
|
|
|
static void EagerLogValue(const Subject* aSubject,
|
2017-10-12 08:15:35 +03:00
|
|
|
DDLogCategory aCategory,
|
2017-08-28 02:54:12 +03:00
|
|
|
const char* aLabel,
|
|
|
|
Value&& aValue)
|
|
|
|
{
|
|
|
|
EagerLogValue(DDLoggedTypeTraits<Subject>::Name(),
|
|
|
|
aSubject,
|
2017-10-12 08:15:35 +03:00
|
|
|
aCategory,
|
2017-08-28 02:54:12 +03:00
|
|
|
aLabel,
|
|
|
|
Forward<Value>(aValue));
|
|
|
|
}
|
|
|
|
|
2017-10-12 09:51:41 +03:00
|
|
|
// EagerLogValue that can explicitly take strings, as the templated function
|
|
|
|
// above confuses Variant when forwarding string literals.
|
2017-08-28 02:54:12 +03:00
|
|
|
static void EagerLogValue(const char* aSubjectTypeName,
|
|
|
|
const void* aSubjectPointer,
|
2017-10-12 08:15:35 +03:00
|
|
|
DDLogCategory aCategory,
|
2017-08-28 02:54:12 +03:00
|
|
|
const char* aLabel,
|
2017-10-12 09:51:41 +03:00
|
|
|
const char* aValue)
|
2017-08-28 02:54:12 +03:00
|
|
|
{
|
2017-10-12 09:51:41 +03:00
|
|
|
Log(aSubjectTypeName,
|
|
|
|
aSubjectPointer,
|
|
|
|
aCategory,
|
|
|
|
aLabel,
|
|
|
|
DDLogValue{ aValue });
|
2017-08-28 02:54:12 +03:00
|
|
|
}
|
|
|
|
|
2017-10-12 09:51:41 +03:00
|
|
|
template<typename Subject>
|
2017-08-28 02:54:12 +03:00
|
|
|
static void EagerLogValue(const Subject* aSubject,
|
2017-10-12 08:15:35 +03:00
|
|
|
DDLogCategory aCategory,
|
2017-08-28 02:54:12 +03:00
|
|
|
const char* aLabel,
|
2017-10-12 09:51:41 +03:00
|
|
|
const char* aValue)
|
2017-08-28 02:54:12 +03:00
|
|
|
{
|
2017-10-12 08:15:35 +03:00
|
|
|
EagerLogValue(
|
2017-10-12 09:51:41 +03:00
|
|
|
DDLoggedTypeTraits<Subject>::Name(), aSubject, aCategory, aLabel, aValue);
|
2017-08-28 02:54:12 +03:00
|
|
|
}
|
|
|
|
|
2017-10-13 08:31:28 +03:00
|
|
|
static void EagerLogPrintf(const char* aSubjectTypeName,
|
|
|
|
const void* aSubjectPointer,
|
|
|
|
DDLogCategory aCategory,
|
|
|
|
const char* aLabel,
|
|
|
|
const char* aString)
|
|
|
|
{
|
|
|
|
Log(aSubjectTypeName,
|
|
|
|
aSubjectPointer,
|
|
|
|
aCategory,
|
|
|
|
aLabel,
|
|
|
|
DDLogValue{ nsCString{ aString } });
|
|
|
|
}
|
|
|
|
|
2017-08-28 02:54:12 +03:00
|
|
|
template<typename... Args>
|
|
|
|
static void EagerLogPrintf(const char* aSubjectTypeName,
|
|
|
|
const void* aSubjectPointer,
|
2017-10-12 08:15:35 +03:00
|
|
|
DDLogCategory aCategory,
|
2017-08-28 02:54:12 +03:00
|
|
|
const char* aLabel,
|
|
|
|
const char* aFormat,
|
|
|
|
Args&&... aArgs)
|
|
|
|
{
|
|
|
|
Log(aSubjectTypeName,
|
|
|
|
aSubjectPointer,
|
2017-10-12 08:15:35 +03:00
|
|
|
aCategory,
|
2017-08-28 02:54:12 +03:00
|
|
|
aLabel,
|
|
|
|
DDLogValue{
|
|
|
|
nsCString{ nsPrintfCString(aFormat, Forward<Args>(aArgs)...) } });
|
|
|
|
}
|
|
|
|
|
2017-10-13 08:31:28 +03:00
|
|
|
template<typename Subject>
|
|
|
|
static void EagerLogPrintf(const Subject* aSubject,
|
|
|
|
DDLogCategory aCategory,
|
|
|
|
const char* aLabel,
|
|
|
|
const char* aString)
|
|
|
|
{
|
|
|
|
EagerLogPrintf(DDLoggedTypeTraits<Subject>::Name(),
|
|
|
|
aSubject,
|
|
|
|
aCategory,
|
|
|
|
aLabel,
|
|
|
|
aString);
|
|
|
|
}
|
|
|
|
|
2017-08-28 02:54:12 +03:00
|
|
|
template<typename Subject, typename... Args>
|
|
|
|
static void EagerLogPrintf(const Subject* aSubject,
|
2017-10-12 08:15:35 +03:00
|
|
|
DDLogCategory aCategory,
|
2017-08-28 02:54:12 +03:00
|
|
|
const char* aLabel,
|
|
|
|
const char* aFormat,
|
|
|
|
Args&&... aArgs)
|
|
|
|
{
|
|
|
|
EagerLogPrintf(DDLoggedTypeTraits<Subject>::Name(),
|
|
|
|
aSubject,
|
2017-10-12 08:15:35 +03:00
|
|
|
aCategory,
|
2017-08-28 02:54:12 +03:00
|
|
|
aLabel,
|
|
|
|
aFormat,
|
|
|
|
Forward<Args>(aArgs)...);
|
|
|
|
}
|
|
|
|
|
2017-10-13 08:31:28 +03:00
|
|
|
static void MozLogPrintf(const char* aSubjectTypeName,
|
|
|
|
const void* aSubjectPointer,
|
|
|
|
const LogModule* aLogModule,
|
|
|
|
LogLevel aLogLevel,
|
|
|
|
const char* aString)
|
|
|
|
{
|
|
|
|
Log(aSubjectTypeName,
|
|
|
|
aSubjectPointer,
|
|
|
|
CategoryForMozLogLevel(aLogLevel),
|
|
|
|
aLogModule->Name(), // LogModule name as label.
|
|
|
|
DDLogValue{ nsCString{ aString } });
|
|
|
|
MOZ_LOG(aLogModule,
|
|
|
|
aLogLevel,
|
|
|
|
("%s[%p] %s", aSubjectTypeName, aSubjectPointer, aString));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename... Args>
|
|
|
|
static void MozLogPrintf(const char* aSubjectTypeName,
|
|
|
|
const void* aSubjectPointer,
|
|
|
|
const LogModule* aLogModule,
|
|
|
|
LogLevel aLogLevel,
|
|
|
|
const char* aFormat,
|
|
|
|
Args&&... aArgs)
|
|
|
|
{
|
|
|
|
nsCString printed = nsPrintfCString(aFormat, Forward<Args>(aArgs)...);
|
|
|
|
Log(aSubjectTypeName,
|
|
|
|
aSubjectPointer,
|
|
|
|
CategoryForMozLogLevel(aLogLevel),
|
|
|
|
aLogModule->Name(), // LogModule name as label.
|
|
|
|
DDLogValue{ printed });
|
|
|
|
MOZ_LOG(aLogModule,
|
|
|
|
aLogLevel,
|
|
|
|
("%s[%p] %s", aSubjectTypeName, aSubjectPointer, printed.get()));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Subject>
|
|
|
|
static void MozLogPrintf(const Subject* aSubject,
|
|
|
|
const LogModule* aLogModule,
|
|
|
|
LogLevel aLogLevel,
|
|
|
|
const char* aString)
|
|
|
|
{
|
|
|
|
MozLogPrintf(DDLoggedTypeTraits<Subject>::Name(),
|
|
|
|
aSubject,
|
|
|
|
aLogModule,
|
|
|
|
aLogLevel,
|
|
|
|
aString);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Subject, typename... Args>
|
|
|
|
static void MozLogPrintf(const Subject* aSubject,
|
|
|
|
const LogModule* aLogModule,
|
|
|
|
LogLevel aLogLevel,
|
|
|
|
const char* aFormat,
|
|
|
|
Args&&... aArgs)
|
|
|
|
{
|
|
|
|
MozLogPrintf(DDLoggedTypeTraits<Subject>::Name(),
|
|
|
|
aSubject,
|
|
|
|
aLogModule,
|
|
|
|
aLogLevel,
|
|
|
|
aFormat,
|
|
|
|
Forward<Args>(aArgs)...);
|
|
|
|
}
|
|
|
|
|
2017-08-28 02:54:12 +03:00
|
|
|
// Special logging functions. Consider using DecoderDoctorLifeLogger to
|
|
|
|
// automatically capture constructions & destructions.
|
|
|
|
|
|
|
|
static void LogConstruction(const char* aSubjectTypeName,
|
|
|
|
const void* aSubjectPointer)
|
|
|
|
{
|
|
|
|
Log(aSubjectTypeName,
|
|
|
|
aSubjectPointer,
|
2017-10-12 08:15:35 +03:00
|
|
|
DDLogCategory::_Construction,
|
2017-08-28 02:54:12 +03:00
|
|
|
"",
|
|
|
|
DDLogValue{ DDNoValue{} });
|
|
|
|
}
|
|
|
|
|
|
|
|
static void LogConstructionAndBase(const char* aSubjectTypeName,
|
|
|
|
const void* aSubjectPointer,
|
|
|
|
const char* aBaseTypeName,
|
|
|
|
const void* aBasePointer)
|
|
|
|
{
|
|
|
|
Log(aSubjectTypeName,
|
|
|
|
aSubjectPointer,
|
2017-10-12 08:15:35 +03:00
|
|
|
DDLogCategory::_DerivedConstruction,
|
2017-08-28 02:54:12 +03:00
|
|
|
"",
|
|
|
|
DDLogValue{ DDLogObject{ aBaseTypeName, aBasePointer } });
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename B>
|
|
|
|
static void LogConstructionAndBase(const char* aSubjectTypeName,
|
|
|
|
const void* aSubjectPointer,
|
|
|
|
const B* aBase)
|
|
|
|
{
|
|
|
|
Log(aSubjectTypeName,
|
|
|
|
aSubjectPointer,
|
2017-10-12 08:15:35 +03:00
|
|
|
DDLogCategory::_DerivedConstruction,
|
2017-08-28 02:54:12 +03:00
|
|
|
"",
|
|
|
|
DDLogValue{ DDLogObject{ DDLoggedTypeTraits<B>::Name(), aBase } });
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Subject>
|
2018-03-13 00:26:52 +03:00
|
|
|
static void
|
|
|
|
LogConstruction(const Subject* aSubject)
|
2017-08-28 02:54:12 +03:00
|
|
|
{
|
|
|
|
using Traits = DDLoggedTypeTraits<Subject>;
|
|
|
|
if (!Traits::HasBase::value) {
|
|
|
|
Log(DDLoggedTypeTraits<Subject>::Name(),
|
|
|
|
aSubject,
|
2017-10-12 08:15:35 +03:00
|
|
|
DDLogCategory::_Construction,
|
2017-08-28 02:54:12 +03:00
|
|
|
"",
|
|
|
|
DDLogValue{ DDNoValue{} });
|
|
|
|
} else {
|
|
|
|
Log(DDLoggedTypeTraits<Subject>::Name(),
|
|
|
|
aSubject,
|
2017-10-12 08:15:35 +03:00
|
|
|
DDLogCategory::_DerivedConstruction,
|
2017-08-28 02:54:12 +03:00
|
|
|
"",
|
|
|
|
DDLogValue{ DDLogObject{
|
|
|
|
DDLoggedTypeTraits<typename Traits::BaseType>::Name(),
|
|
|
|
static_cast<const typename Traits::BaseType*>(aSubject) } });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void LogDestruction(const char* aSubjectTypeName,
|
|
|
|
const void* aSubjectPointer)
|
|
|
|
{
|
|
|
|
Log(aSubjectTypeName,
|
|
|
|
aSubjectPointer,
|
2017-10-12 08:15:35 +03:00
|
|
|
DDLogCategory::_Destruction,
|
2017-08-28 02:54:12 +03:00
|
|
|
"",
|
|
|
|
DDLogValue{ DDNoValue{} });
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Subject>
|
|
|
|
static void LogDestruction(const Subject* aSubject)
|
|
|
|
{
|
|
|
|
Log(DDLoggedTypeTraits<Subject>::Name(),
|
|
|
|
aSubject,
|
2017-10-12 08:15:35 +03:00
|
|
|
DDLogCategory::_Destruction,
|
2017-08-28 02:54:12 +03:00
|
|
|
"",
|
|
|
|
DDLogValue{ DDNoValue{} });
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename P, typename C>
|
|
|
|
static void LinkParentAndChild(const P* aParent,
|
|
|
|
const char* aLinkName,
|
|
|
|
const C* aChild)
|
|
|
|
{
|
|
|
|
if (aChild) {
|
|
|
|
Log(DDLoggedTypeTraits<P>::Name(),
|
|
|
|
aParent,
|
2017-10-12 08:15:35 +03:00
|
|
|
DDLogCategory::_Link,
|
2017-08-28 02:54:12 +03:00
|
|
|
aLinkName,
|
|
|
|
DDLogValue{ DDLogObject{ DDLoggedTypeTraits<C>::Name(), aChild } });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename C>
|
|
|
|
static void LinkParentAndChild(const char* aParentTypeName,
|
|
|
|
const void* aParentPointer,
|
|
|
|
const char* aLinkName,
|
|
|
|
const C* aChild)
|
|
|
|
{
|
|
|
|
if (aChild) {
|
|
|
|
Log(aParentTypeName,
|
|
|
|
aParentPointer,
|
2017-10-12 08:15:35 +03:00
|
|
|
DDLogCategory::_Link,
|
2017-08-28 02:54:12 +03:00
|
|
|
aLinkName,
|
|
|
|
DDLogValue{ DDLogObject{ DDLoggedTypeTraits<C>::Name(), aChild } });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename P>
|
|
|
|
static void LinkParentAndChild(const P* aParent,
|
|
|
|
const char* aLinkName,
|
|
|
|
const char* aChildTypeName,
|
|
|
|
const void* aChildPointer)
|
|
|
|
{
|
|
|
|
if (aChildPointer) {
|
|
|
|
Log(DDLoggedTypeTraits<P>::Name(),
|
|
|
|
aParent,
|
2017-10-12 08:15:35 +03:00
|
|
|
DDLogCategory::_Link,
|
2017-08-28 02:54:12 +03:00
|
|
|
aLinkName,
|
|
|
|
DDLogValue{ DDLogObject{ aChildTypeName, aChildPointer } });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename C>
|
|
|
|
static void UnlinkParentAndChild(const char* aParentTypeName,
|
|
|
|
const void* aParentPointer,
|
|
|
|
const C* aChild)
|
|
|
|
{
|
|
|
|
if (aChild) {
|
|
|
|
Log(aParentTypeName,
|
|
|
|
aParentPointer,
|
2017-10-12 08:15:35 +03:00
|
|
|
DDLogCategory::_Unlink,
|
2017-08-28 02:54:12 +03:00
|
|
|
"",
|
|
|
|
DDLogValue{ DDLogObject{ DDLoggedTypeTraits<C>::Name(), aChild } });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename P, typename C>
|
|
|
|
static void UnlinkParentAndChild(const P* aParent, const C* aChild)
|
|
|
|
{
|
|
|
|
if (aChild) {
|
|
|
|
Log(DDLoggedTypeTraits<P>::Name(),
|
|
|
|
aParent,
|
2017-10-12 08:15:35 +03:00
|
|
|
DDLogCategory::_Unlink,
|
2017-08-28 02:54:12 +03:00
|
|
|
"",
|
|
|
|
DDLogValue{ DDLogObject{ DDLoggedTypeTraits<C>::Name(), aChild } });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Retrieval functions.
|
|
|
|
|
|
|
|
// Enable logging, if not done already. No effect otherwise.
|
|
|
|
static void EnableLogging();
|
|
|
|
|
|
|
|
using LogMessagesPromise =
|
|
|
|
MozPromise<nsCString, nsresult, /* IsExclusive = */ true>;
|
|
|
|
|
|
|
|
// Retrieve all messages related to a given HTMLMediaElement object.
|
|
|
|
// This call will trigger a processing run (to ensure the most recent data
|
|
|
|
// will be returned), and the returned promise will be resolved with all
|
|
|
|
// relevant log messages and object lifetimes in a JSON string.
|
|
|
|
// The first call will enable logging, until shutdown.
|
|
|
|
static RefPtr<LogMessagesPromise> RetrieveMessages(
|
|
|
|
const dom::HTMLMediaElement* aMediaElement);
|
|
|
|
|
|
|
|
private:
|
|
|
|
// If logging is not enabled yet, initiate it, return true.
|
|
|
|
// If logging has been shutdown, don't start it, return false.
|
|
|
|
// Otherwise return true.
|
|
|
|
static bool EnsureLogIsEnabled();
|
|
|
|
|
|
|
|
// Note that this call may block while the state is scEnabling;
|
|
|
|
// set aDontBlock to true to avoid blocking, most importantly when the
|
|
|
|
// caller is the one doing the enabling, this would cause an endless loop.
|
|
|
|
static void PanicInternal(const char* aReason, bool aDontBlock);
|
|
|
|
|
|
|
|
static void Log(const char* aSubjectTypeName,
|
|
|
|
const void* aSubjectPointer,
|
2017-10-12 08:15:35 +03:00
|
|
|
DDLogCategory aCategory,
|
2017-08-28 02:54:12 +03:00
|
|
|
const char* aLabel,
|
|
|
|
DDLogValue&& aValue);
|
|
|
|
|
2017-10-13 08:31:28 +03:00
|
|
|
static void Log(const char* aSubjectTypeName,
|
|
|
|
const void* aSubjectPointer,
|
|
|
|
const LogModule* aLogModule,
|
|
|
|
LogLevel aLogLevel,
|
|
|
|
DDLogValue&& aValue);
|
|
|
|
|
|
|
|
static DDLogCategory CategoryForMozLogLevel(LogLevel aLevel)
|
|
|
|
{
|
|
|
|
switch (aLevel) {
|
|
|
|
default:
|
|
|
|
case LogLevel::Error:
|
|
|
|
return DDLogCategory::MozLogError;
|
|
|
|
case LogLevel::Warning:
|
|
|
|
return DDLogCategory::MozLogWarning;
|
|
|
|
case LogLevel::Info:
|
|
|
|
return DDLogCategory::MozLogInfo;
|
|
|
|
case LogLevel::Debug:
|
|
|
|
return DDLogCategory::MozLogDebug;
|
|
|
|
case LogLevel::Verbose:
|
|
|
|
return DDLogCategory::MozLogVerbose;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-28 02:54:12 +03:00
|
|
|
using LogState = int;
|
|
|
|
// Currently disabled, may be enabled on request.
|
|
|
|
static constexpr LogState scDisabled = 0;
|
|
|
|
// Currently enabled (logging happens), may be shutdown.
|
|
|
|
static constexpr LogState scEnabled = 1;
|
|
|
|
// Still disabled, but one thread is working on enabling it, nobody else
|
|
|
|
// should interfere during this time.
|
|
|
|
static constexpr LogState scEnabling = 2;
|
|
|
|
// Shutdown, cannot be re-enabled.
|
|
|
|
static constexpr LogState scShutdown = 3;
|
|
|
|
// Current state.
|
2017-10-12 02:45:03 +03:00
|
|
|
// "ReleaseAcquire" because when changing to scEnabled, the just-created
|
|
|
|
// sMediaLogs must be accessible to consumers that see scEnabled.
|
|
|
|
static Atomic<LogState, ReleaseAcquire> sLogState;
|
2017-08-28 02:54:12 +03:00
|
|
|
|
|
|
|
// If non-null, reason for an abnormal shutdown.
|
|
|
|
static const char* sShutdownReason;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Base class to automatically record a class lifetime. Usage:
|
|
|
|
// class SomeClass : public DecoderDoctorLifeLogger<SomeClass>
|
|
|
|
// {
|
|
|
|
// ...
|
|
|
|
template<typename T>
|
|
|
|
class DecoderDoctorLifeLogger
|
|
|
|
{
|
|
|
|
public:
|
2018-03-13 00:26:52 +03:00
|
|
|
#if defined(__clang__)
|
|
|
|
// This constructor is called before the `T` object is fully constructed, and
|
|
|
|
// pointers are not dereferenced anyway, so UBSan shouldn't check vptrs.
|
|
|
|
__attribute__((no_sanitize("vptr")))
|
|
|
|
#endif
|
2017-08-28 02:54:12 +03:00
|
|
|
DecoderDoctorLifeLogger()
|
|
|
|
{
|
|
|
|
DecoderDoctorLogger::LogConstruction(static_cast<const T*>(this));
|
|
|
|
}
|
2018-03-13 00:26:52 +03:00
|
|
|
#if defined(__clang__)
|
|
|
|
// This destructor is called after the `T` object is partially destructed, and
|
|
|
|
// pointers are not dereferenced anyway, so UBSan shouldn't check vptrs.
|
|
|
|
__attribute__((no_sanitize("vptr")))
|
|
|
|
#endif
|
2017-08-28 02:54:12 +03:00
|
|
|
~DecoderDoctorLifeLogger()
|
|
|
|
{
|
|
|
|
DecoderDoctorLogger::LogDestruction(static_cast<const T*>(this));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Macros to help lazily-evaluate arguments, only after we have checked that
|
|
|
|
// logging is enabled.
|
|
|
|
|
|
|
|
// Log a single value; see DDLogValue for allowed types.
|
2017-10-12 08:15:35 +03:00
|
|
|
#define DDLOG(_category, _label, _arg) \
|
2017-08-28 02:54:12 +03:00
|
|
|
do { \
|
|
|
|
if (DecoderDoctorLogger::IsDDLoggingEnabled()) { \
|
2017-10-12 08:15:35 +03:00
|
|
|
DecoderDoctorLogger::EagerLogValue(this, _category, _label, _arg); \
|
2017-08-28 02:54:12 +03:00
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
// Log a single value, with an EXplicit `this`.
|
2017-10-12 08:15:35 +03:00
|
|
|
#define DDLOGEX(_this, _category, _label, _arg) \
|
2017-08-28 02:54:12 +03:00
|
|
|
do { \
|
|
|
|
if (DecoderDoctorLogger::IsDDLoggingEnabled()) { \
|
2017-10-12 08:15:35 +03:00
|
|
|
DecoderDoctorLogger::EagerLogValue(_this, _category, _label, _arg); \
|
2017-08-28 02:54:12 +03:00
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
// Log a single value, with EXplicit type name and `this`.
|
2017-10-12 08:15:35 +03:00
|
|
|
#define DDLOGEX2(_typename, _this, _category, _label, _arg) \
|
2017-08-28 02:54:12 +03:00
|
|
|
do { \
|
|
|
|
if (DecoderDoctorLogger::IsDDLoggingEnabled()) { \
|
|
|
|
DecoderDoctorLogger::EagerLogValue( \
|
2017-10-12 08:15:35 +03:00
|
|
|
_typename, _this, _category, _label, _arg); \
|
2017-08-28 02:54:12 +03:00
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
// Do a printf format check in DEBUG, with the downside that side-effects (from
|
|
|
|
// evaluating the arguments) may happen twice! Who would do that anyway?
|
|
|
|
static void inline MOZ_FORMAT_PRINTF(1, 2) DDLOGPRCheck(const char*, ...) {}
|
2017-10-13 08:31:28 +03:00
|
|
|
#define DDLOGPR_CHECK(_fmt, ...) DDLOGPRCheck(_fmt, ##__VA_ARGS__)
|
2017-08-28 02:54:12 +03:00
|
|
|
#else
|
|
|
|
#define DDLOGPR_CHECK(_fmt, ...)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Log a printf'd string. Discouraged, please try using DDLOG instead.
|
2017-10-12 08:15:35 +03:00
|
|
|
#define DDLOGPR(_category, _label, _format, ...) \
|
2017-08-28 02:54:12 +03:00
|
|
|
do { \
|
|
|
|
if (DecoderDoctorLogger::IsDDLoggingEnabled()) { \
|
2017-10-13 08:31:28 +03:00
|
|
|
DDLOGPR_CHECK(_format, ##__VA_ARGS__); \
|
2017-08-28 02:54:12 +03:00
|
|
|
DecoderDoctorLogger::EagerLogPrintf( \
|
2017-10-13 08:31:28 +03:00
|
|
|
this, _category, _label, _format, ##__VA_ARGS__); \
|
2017-08-28 02:54:12 +03:00
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
// Link a child object.
|
|
|
|
#define DDLINKCHILD(...) \
|
|
|
|
do { \
|
|
|
|
if (DecoderDoctorLogger::IsDDLoggingEnabled()) { \
|
|
|
|
DecoderDoctorLogger::LinkParentAndChild(this, __VA_ARGS__); \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
// Unlink a child object.
|
|
|
|
#define DDUNLINKCHILD(...) \
|
|
|
|
do { \
|
|
|
|
if (DecoderDoctorLogger::IsDDLoggingEnabled()) { \
|
|
|
|
DecoderDoctorLogger::UnlinkParentAndChild(this, __VA_ARGS__); \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2017-10-13 08:31:28 +03:00
|
|
|
// Log a printf'd string to DDLogger and/or MOZ_LOG, with an EXplicit `this`.
|
|
|
|
// Don't even call MOZ_LOG on Android non-release/beta; See Logging.h.
|
|
|
|
#if !defined(ANDROID) || !defined(RELEASE_OR_BETA)
|
|
|
|
#define DDMOZ_LOGEX(_this, _logModule, _logLevel, _format, ...) \
|
|
|
|
do { \
|
|
|
|
if (DecoderDoctorLogger::IsDDLoggingEnabled() || \
|
|
|
|
MOZ_LOG_TEST(_logModule, _logLevel)) { \
|
|
|
|
DDLOGPR_CHECK(_format, ##__VA_ARGS__); \
|
|
|
|
DecoderDoctorLogger::MozLogPrintf( \
|
|
|
|
_this, _logModule, _logLevel, _format, ##__VA_ARGS__); \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
#else
|
|
|
|
#define DDMOZ_LOGEX(_this, _logModule, _logLevel, _format, ...) \
|
|
|
|
do { \
|
|
|
|
if (DecoderDoctorLogger::IsDDLoggingEnabled()) { \
|
|
|
|
DDLOGPR_CHECK(_format, ##__VA_ARGS__); \
|
|
|
|
DecoderDoctorLogger::MozLogPrintf( \
|
|
|
|
_this, _logModule, _logLevel, _format, ##__VA_ARGS__); \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Log a printf'd string to DDLogger and/or MOZ_LOG.
|
|
|
|
#define DDMOZ_LOG(_logModule, _logLevel, _format, ...) \
|
|
|
|
DDMOZ_LOGEX(this, _logModule, _logLevel, _format, ##__VA_ARGS__)
|
|
|
|
|
2017-08-28 02:54:12 +03:00
|
|
|
} // namespace mozilla
|
|
|
|
|
|
|
|
#endif // DecoderDoctorLogger_h_
|