Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
/* 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 Telemetry_h__
#define Telemetry_h__
#include "mozilla/Maybe.h"
#include "mozilla/TelemetryEventEnums.h"
#include "mozilla/TelemetryHistogramEnums.h"
#include "mozilla/TelemetryScalarEnums.h"
#include "mozilla/TimeStamp.h"
#include "nsString.h"
#include "nsTArray.h"
#include "nsXULAppAPI.h"
/******************************************************************************
* This implements the Telemetry system.
* It allows recording into histograms as well some more specialized data
* points and gives access to the data.
*
* For documentation on how to add and use new Telemetry probes, see:
*
* For more general information on Telemetry see:
*****************************************************************************/
namespace mozilla {
namespace Telemetry {
struct HistogramAccumulation;
struct KeyedHistogramAccumulation;
struct ScalarAction;
struct KeyedScalarAction;
struct ChildEventData;
struct EventExtraEntry {
nsCString key;
nsCString value;
};
/**
* Initialize the Telemetry service on the main thread at startup.
*/
void Init();
/**
* Shutdown the Telemetry service.
*/
void ShutdownTelemetry();
/**
* Adds sample to a histogram defined in TelemetryHistogramEnums.h
*
* @param id - histogram id
* @param sample - value to record.
*/
void Accumulate(HistogramID id, uint32_t sample);
/**
* Adds an array of samples to a histogram defined in TelemetryHistograms.h
* @param id - histogram id
* @param samples - values to record.
*/
void Accumulate(HistogramID id, const nsTArray<uint32_t>& samples);
/**
* Adds sample to a keyed histogram defined in TelemetryHistogramEnums.h
*
* @param id - keyed histogram id
* @param key - the string key
* @param sample - (optional) value to record, defaults to 1.
*/
void Accumulate(HistogramID id, const nsCString& key, uint32_t sample = 1);
/**
* Adds an array of samples to a histogram defined in TelemetryHistograms.h
* @param id - histogram id
* @param samples - values to record.
* @param key - the string key
*/
void Accumulate(HistogramID id, const nsCString& key,
const nsTArray<uint32_t>& samples);
/**
* Adds a sample to a histogram defined in TelemetryHistogramEnums.h.
* This function is here to support telemetry measurements from Java,
* where we have only names and not numeric IDs. You should almost
* certainly be using the by-enum-id version instead of this one.
*
* @param name - histogram name
* @param sample - value to record
*/
void Accumulate(const char* name, uint32_t sample);
/**
* Adds a sample to a histogram defined in TelemetryHistogramEnums.h.
* This function is here to support telemetry measurements from Java,
* where we have only names and not numeric IDs. You should almost
* certainly be using the by-enum-id version instead of this one.
*
* @param name - histogram name
* @param key - the string key
* @param sample - sample - (optional) value to record, defaults to 1.
*/
void Accumulate(const char* name, const nsCString& key, uint32_t sample = 1);
/**
* Adds sample to a categorical histogram defined in TelemetryHistogramEnums.h
* This is the typesafe - and preferred - way to use the categorical histograms
* by passing values from the corresponding Telemetry::LABELS_* enum.
*
* @param enumValue - Label value from one of the Telemetry::LABELS_* enums.
*/
template <class E>
void AccumulateCategorical(E enumValue) {
static_assert(IsCategoricalLabelEnum<E>::value,
"Only categorical label enum types are supported.");
Accumulate(static_cast<HistogramID>(CategoricalLabelId<E>::value),
static_cast<uint32_t>(enumValue));
};
/**
* Adds an array of samples to categorical histograms defined in
* TelemetryHistogramEnums.h This is the typesafe - and preferred - way to use
* the categorical histograms by passing values from the corresponding
* Telemetry::LABELS_* enums.
*
* @param enumValues - Array of labels from Telemetry::LABELS_* enums.
*/
template <class E>
void AccumulateCategorical(const nsTArray<E>& enumValues) {
static_assert(IsCategoricalLabelEnum<E>::value,
"Only categorical label enum types are supported.");
nsTArray<uint32_t> intSamples(enumValues.Length());
for (E aValue : enumValues) {
intSamples.AppendElement(static_cast<uint32_t>(aValue));
}
HistogramID categoricalId =
static_cast<HistogramID>(CategoricalLabelId<E>::value);
Accumulate(categoricalId, intSamples);
}
/**
* Adds sample to a keyed categorical histogram defined in
* TelemetryHistogramEnums.h This is the typesafe - and preferred - way to use
* the keyed categorical histograms by passing values from the corresponding
* Telemetry::LABELS_* enum.
*
* @param key - the string key
* @param enumValue - Label value from one of the Telemetry::LABELS_* enums.
*/
template <class E>
void AccumulateCategoricalKeyed(const nsCString& key, E enumValue) {
static_assert(IsCategoricalLabelEnum<E>::value,
"Only categorical label enum types are supported.");
Accumulate(static_cast<HistogramID>(CategoricalLabelId<E>::value), key,
static_cast<uint32_t>(enumValue));
};
/**
* Adds an array of samples to a keyed categorical histogram defined in
* TelemetryHistogramEnums.h. This is the typesafe - and preferred - way to use
* the keyed categorical histograms by passing values from the corresponding
* Telemetry::LABELS_*enum.
*
* @param key - the string key
* @param enumValue - Label value from one of the Telemetry::LABELS_* enums.
*/
template <class E>
void AccumulateCategoricalKeyed(const nsCString& key,
const nsTArray<E>& enumValues) {
static_assert(IsCategoricalLabelEnum<E>::value,
"Only categorical label enum types are supported.");
nsTArray<uint32_t> intSamples(enumValues.Length());
for (E aValue : enumValues) {
intSamples.AppendElement(static_cast<uint32_t>(aValue));
}
Accumulate(static_cast<HistogramID>(CategoricalLabelId<E>::value), key,
intSamples);
};
/**
* Adds sample to a categorical histogram defined in TelemetryHistogramEnums.h
* This string will be matched against the labels defined in Histograms.json.
* If the string does not match a label defined for the histogram, nothing will
* be recorded.
*
* @param id - The histogram id.
* @param label - A string label value that is defined in Histograms.json for
* this histogram.
*/
void AccumulateCategorical(HistogramID id, const nsCString& label);
/**
* Adds an array of samples to a categorical histogram defined in
* Histograms.json
*
* @param id - The histogram id
* @param labels - The array of labels to accumulate
*/
void AccumulateCategorical(HistogramID id, const nsTArray<nsCString>& labels);
/**
* Adds time delta in milliseconds to a histogram defined in
* TelemetryHistogramEnums.h
*
* @param id - histogram id
* @param start - start time
* @param end - end time
*/
void AccumulateTimeDelta(HistogramID id, TimeStamp start,
TimeStamp end = TimeStamp::Now());
/**
* Adds time delta in milliseconds to a keyed histogram defined in
* TelemetryHistogramEnums.h
*
* @param id - histogram id
* @param key - the string key
* @param start - start time
* @param end - end time
*/
void AccumulateTimeDelta(HistogramID id, const nsCString& key, TimeStamp start,
TimeStamp end = TimeStamp::Now());
/**
* Enable/disable recording for this histogram in this process at runtime.
* Recording is enabled by default, unless listed at
* kRecordingInitiallyDisabledIDs[]. id must be a valid telemetry enum,
*
* @param id - histogram id
* @param enabled - whether or not to enable recording from now on.
*/
void SetHistogramRecordingEnabled(HistogramID id, bool enabled);
const char* GetHistogramName(HistogramID id);
class MOZ_RAII RuntimeAutoTimer {
public:
explicit RuntimeAutoTimer(Telemetry::HistogramID aId,
TimeStamp aStart = TimeStamp::Now())
: id(aId), start(aStart) {}
explicit RuntimeAutoTimer(Telemetry::HistogramID aId, const nsCString& aKey,
TimeStamp aStart = TimeStamp::Now())
: id(aId), key(aKey), start(aStart) {
MOZ_ASSERT(!aKey.IsEmpty(), "The key must not be empty.");
}
~RuntimeAutoTimer() {
if (key.IsEmpty()) {
AccumulateTimeDelta(id, start);
} else {
AccumulateTimeDelta(id, key, start);
}
}
private:
Telemetry::HistogramID id;
const nsCString key;
const TimeStamp start;
};
template <HistogramID id>
class MOZ_RAII AutoTimer {
public:
explicit AutoTimer(TimeStamp aStart = TimeStamp::Now()) : start(aStart) {}
explicit AutoTimer(const nsCString& aKey, TimeStamp aStart = TimeStamp::Now())
: start(aStart), key(aKey) {
MOZ_ASSERT(!aKey.IsEmpty(), "The key must not be empty.");
}
~AutoTimer() {
if (key.IsEmpty()) {
AccumulateTimeDelta(id, start);
} else {
AccumulateTimeDelta(id, key, start);
}
}
private:
const TimeStamp start;
const nsCString key;
};
class MOZ_RAII RuntimeAutoCounter {
public:
explicit RuntimeAutoCounter(HistogramID aId, uint32_t counterStart = 0)
: id(aId), counter(counterStart) {}
~RuntimeAutoCounter() { Accumulate(id, counter); }
// Prefix increment only, to encourage good habits.
void operator++() {
if (NS_WARN_IF(counter == std::numeric_limits<uint32_t>::max())) {
return;
}
++counter;
}
// Chaining doesn't make any sense, don't return anything.
void operator+=(int increment) {
if (NS_WARN_IF(increment > 0 &&
static_cast<uint32_t>(increment) >
(std::numeric_limits<uint32_t>::max() - counter))) {
counter = std::numeric_limits<uint32_t>::max();
return;
}
if (NS_WARN_IF(increment < 0 &&
static_cast<uint32_t>(-increment) > counter)) {
counter = std::numeric_limits<uint32_t>::min();
return;
}
counter += increment;
}
private:
HistogramID id;
uint32_t counter;
};
template <HistogramID id>
class MOZ_RAII AutoCounter {
public:
explicit AutoCounter(uint32_t counterStart = 0) : counter(counterStart) {}
~AutoCounter() { Accumulate(id, counter); }
// Prefix increment only, to encourage good habits.
void operator++() {
if (NS_WARN_IF(counter == std::numeric_limits<uint32_t>::max())) {
return;
}
++counter;
}
// Chaining doesn't make any sense, don't return anything.
void operator+=(int increment) {
if (NS_WARN_IF(increment > 0 &&
static_cast<uint32_t>(increment) >
(std::numeric_limits<uint32_t>::max() - counter))) {
counter = std::numeric_limits<uint32_t>::max();
return;
}
if (NS_WARN_IF(increment < 0 &&
static_cast<uint32_t>(-increment) > counter)) {
counter = std::numeric_limits<uint32_t>::min();
return;
}
counter += increment;
}
private:
uint32_t counter;
};
/**
* Indicates whether Telemetry base data recording is turned on. Added for
* future uses.
*/
bool CanRecordBase();
/**
* Indicates whether Telemetry extended data recording is turned on. This is
* intended to guard calls to Accumulate when the statistic being recorded is
* expensive to compute.
*/
bool CanRecordExtended();
/**
* Indicates whether Telemetry release data recording is turned on. Usually
* true.
*
* @see nsITelemetry.canRecordReleaseData
*/
bool CanRecordReleaseData();
/**
* Indicates whether Telemetry pre-release data recording is turned on. Tends
* to be true on pre-release channels.
*
* @see nsITelemetry.canRecordPrereleaseData
*/
bool CanRecordPrereleaseData();
/**
* Records slow SQL statements for Telemetry reporting.
*
* @param statement - offending SQL statement to record
* @param dbName - DB filename
* @param delay - execution time in milliseconds
*/
void RecordSlowSQLStatement(const nsACString& statement,
const nsACString& dbName, uint32_t delay);
/**
* Initialize I/O Reporting
* Initially this only records I/O for files in the binary directory.
*
* @param aXreDir - XRE directory
*/
void InitIOReporting(nsIFile* aXreDir);
/**
* Set the profile directory. Once called, files in the profile directory will
* be included in I/O reporting. We can't use the directory
* service to obtain this information because it isn't running yet.
*/
void SetProfileDir(nsIFile* aProfD);
/**
* Called to inform Telemetry that startup has completed.
*/
void LeavingStartupStage();
/**
* Called to inform Telemetry that shutdown is commencing.
*/
void EnteringShutdownStage();
/**
* Thresholds for a statement to be considered slow, in milliseconds
*/
const uint32_t kSlowSQLThresholdForMainThread = 50;
const uint32_t kSlowSQLThresholdForHelperThreads = 100;
/**
* Record a failed attempt at locking the user's profile.
*
* @param aProfileDir The profile directory whose lock attempt failed
*/
void WriteFailedProfileLock(nsIFile* aProfileDir);
/**
* Adds the value to the given scalar.
*
* @param aId The scalar enum id.
* @param aValue The value to add to the scalar.
*/
void ScalarAdd(mozilla::Telemetry::ScalarID aId, uint32_t aValue);
/**
* Sets the scalar to the given value.
*
* @param aId The scalar enum id.
* @param aValue The value to set the scalar to.
*/
void ScalarSet(mozilla::Telemetry::ScalarID aId, uint32_t aValue);
/**
* Sets the scalar to the given value.
*
* @param aId The scalar enum id.
* @param aValue The value to set the scalar to.
*/
void ScalarSet(mozilla::Telemetry::ScalarID aId, bool aValue);
/**
* Sets the scalar to the given value.
*
* @param aId The scalar enum id.
* @param aValue The value to set the scalar to, truncated to
* 50 characters if exceeding that length.
*/
void ScalarSet(mozilla::Telemetry::ScalarID aId, const nsAString& aValue);
/**
* Sets the scalar to the maximum of the current and the passed value.
*
* @param aId The scalar enum id.
* @param aValue The value the scalar is set to if its greater
* than the current value.
*/
void ScalarSetMaximum(mozilla::Telemetry::ScalarID aId, uint32_t aValue);
/**
* Adds the value to the given scalar.
*
* @param aId The scalar enum id.
* @param aKey The scalar key.
* @param aValue The value to add to the scalar.
*/
void ScalarAdd(mozilla::Telemetry::ScalarID aId, const nsAString& aKey,
uint32_t aValue);
/**
* Sets the scalar to the given value.
*
* @param aId The scalar enum id.
* @param aKey The scalar key.
* @param aValue The value to set the scalar to.
*/
void ScalarSet(mozilla::Telemetry::ScalarID aId, const nsAString& aKey,
uint32_t aValue);
/**
* Sets the scalar to the given value.
*
* @param aId The scalar enum id.
* @param aKey The scalar key.
* @param aValue The value to set the scalar to.
*/
void ScalarSet(mozilla::Telemetry::ScalarID aId, const nsAString& aKey,
bool aValue);
/**
* Sets the scalar to the maximum of the current and the passed value.
*
* @param aId The scalar enum id.
* @param aKey The scalar key.
* @param aValue The value the scalar is set to if its greater
* than the current value.
*/
void ScalarSetMaximum(mozilla::Telemetry::ScalarID aId, const nsAString& aKey,
uint32_t aValue);
template <ScalarID id>
class MOZ_RAII AutoScalarTimer {
public:
explicit AutoScalarTimer(TimeStamp aStart = TimeStamp::Now())
: start(aStart) {}
explicit AutoScalarTimer(const nsAString& aKey,
TimeStamp aStart = TimeStamp::Now())
: start(aStart), key(aKey) {
MOZ_ASSERT(!aKey.IsEmpty(), "The key must not be empty.");
}
~AutoScalarTimer() {
TimeStamp end = TimeStamp::Now();
uint32_t delta = static_cast<uint32_t>((end - start).ToMilliseconds());
if (key.IsEmpty()) {
mozilla::Telemetry::ScalarSet(id, delta);
} else {
mozilla::Telemetry::ScalarSet(id, key, delta);
}
}
private:
const TimeStamp start;
const nsString key;
};
/**
* Records an event. See the Event documentation for more information:
*
* @param aId The event enum id.
* @param aValue Optional. The event value.
* @param aExtra Optional. The event's extra key/value pairs.
*/
void RecordEvent(mozilla::Telemetry::EventID aId,
const mozilla::Maybe<nsCString>& aValue,
const mozilla::Maybe<CopyableTArray<EventExtraEntry>>& aExtra);
/**
* Enables recording of events in a category.
* Events default to recording disabled.
* This toggles recording for all events in the specified category.
*
* @param aCategory The category name.
* @param aEnabled Whether recording should be enabled or disabled.
*/
void SetEventRecordingEnabled(const nsACString& aCategory, bool aEnabled);
} // namespace Telemetry
} // namespace mozilla
#endif // Telemetry_h__