@mozilla/glean
Advanced tools
Comparing version 1.3.0 to 3.0.0
@@ -11,3 +11,3 @@ #!/usr/bin/env node | ||
const VIRTUAL_ENVIRONMENT_DIR = process.env.VIRTUAL_ENV || path.join(process.cwd(), ".venv"); | ||
const GLEAN_PARSER_VERSION = "6.2.1"; | ||
const GLEAN_PARSER_VERSION = "10.0.3"; | ||
const PYTHON_SCRIPT = ` | ||
@@ -26,16 +26,39 @@ import importlib | ||
found_version = getattr(module, '__version__') | ||
if found_version != expected_version: | ||
if not offline: | ||
subprocess.check_call([ | ||
sys.executable, | ||
'-m', | ||
'pip', | ||
'install', | ||
'--upgrade', | ||
f'{module_name}=={expected_version}' | ||
]) | ||
if not offline: | ||
# When running in online mode, we always install. | ||
# If it is installed this is essentially a no-op, | ||
# otherwise it installs/upgrades. | ||
if 'git' in expected_version: | ||
target=expected_version | ||
else: | ||
print(f'Using Python environment at {sys.executable},') | ||
print(f'expected glean_parser version {expected_version}, found {found_version}.') | ||
target=f'{module_name}~={expected_version}' | ||
subprocess.check_call([ | ||
sys.executable, | ||
'-m', | ||
'pip', | ||
'install', | ||
'--upgrade', | ||
target | ||
]) | ||
else: | ||
error_text = f''' | ||
Using Python environment at {sys.executable}, | ||
expected glean_parser version ~={expected_version}, found {found_version}. | ||
''' | ||
if found_version is None: | ||
print(error_text) | ||
sys.exit(1) | ||
else: | ||
# We check MAJOR.MINOR only | ||
expected_ver = expected_version.split('.') | ||
expected_maj, expected_min = int(expected_ver[0]), int(expected_ver[1]) | ||
current_ver = found_version.split('.') | ||
current_maj, current_min = int(current_ver[0]), int(current_ver[1]) | ||
if current_maj > expected_maj or current_maj < expected_maj or (current_maj == expected_maj and current_min < expected_min): | ||
print(error_text) | ||
sys.exit(1) | ||
try: | ||
@@ -55,2 +78,5 @@ subprocess.check_call([ | ||
} | ||
function getPipBinName() { | ||
return (platform === "win32") ? "pip3.exe" : "pip3"; | ||
} | ||
function getPythonVenvBinariesPath(venvRoot) { | ||
@@ -63,4 +89,6 @@ if (platform === "win32") { | ||
async function checkPythonVenvExists(venvPath) { | ||
var _a; | ||
log(LOG_TAG, `Checking for a virtual environment at ${venvPath}`); | ||
const venvPython = path.join(getPythonVenvBinariesPath(venvPath), getSystemPythonBinName()); | ||
const pythonBinary = (_a = process.env.GLEAN_PYTHON) !== null && _a !== void 0 ? _a : getSystemPythonBinName(); | ||
const venvPython = path.join(getPythonVenvBinariesPath(venvPath), pythonBinary); | ||
const access = promisify(fs.access); | ||
@@ -77,7 +105,9 @@ try { | ||
async function createPythonVenv(venvPath) { | ||
var _a, _b; | ||
log(LOG_TAG, `Creating a virtual environment at ${venvPath}`); | ||
const pipFilename = (platform === "win32") ? "pip3.exe" : "pip3"; | ||
const pipFilename = (_a = process.env.GLEAN_PIP) !== null && _a !== void 0 ? _a : getPipBinName(); | ||
const venvPip = path.join(getPythonVenvBinariesPath(VIRTUAL_ENVIRONMENT_DIR), pipFilename); | ||
const pipCmd = `${venvPip} install wheel`; | ||
const venvCmd = `${getSystemPythonBinName()} -m venv ${VIRTUAL_ENVIRONMENT_DIR}`; | ||
const pythonBinary = (_b = process.env.GLEAN_PYTHON) !== null && _b !== void 0 ? _b : getSystemPythonBinName(); | ||
const venvCmd = `${pythonBinary} -m venv ${VIRTUAL_ENVIRONMENT_DIR}`; | ||
for (const cmd of [venvCmd, pipCmd]) { | ||
@@ -108,4 +138,6 @@ const spinner = getStartedSpinner(); | ||
async function runGlean(parserArgs) { | ||
var _a; | ||
const spinner = getStartedSpinner(); | ||
const pythonBin = path.join(getPythonVenvBinariesPath(VIRTUAL_ENVIRONMENT_DIR), getSystemPythonBinName()); | ||
const pythonBinary = (_a = process.env.GLEAN_PYTHON) !== null && _a !== void 0 ? _a : getSystemPythonBinName(); | ||
const pythonBin = path.join(getPythonVenvBinariesPath(VIRTUAL_ENVIRONMENT_DIR), pythonBinary); | ||
const isOnlineArg = process.env.OFFLINE ? "offline" : "online"; | ||
@@ -112,0 +144,0 @@ let tmpDir = ""; |
@@ -6,3 +6,3 @@ import { DEFAULT_TELEMETRY_ENDPOINT, GLEAN_MAX_SOURCE_TAGS } from "./constants.js"; | ||
const LOG_TAG = "core.Config"; | ||
const DEFAULT_MAX_EVENTS = 500; | ||
const DEFAULT_MAX_EVENTS = 1; | ||
export class Configuration { | ||
@@ -14,6 +14,5 @@ constructor(config) { | ||
this.appDisplayVersion = config === null || config === void 0 ? void 0 : config.appDisplayVersion; | ||
this.architecture = config === null || config === void 0 ? void 0 : config.architecture; | ||
this.osVersion = config === null || config === void 0 ? void 0 : config.osVersion; | ||
this.buildDate = config === null || config === void 0 ? void 0 : config.buildDate; | ||
this.maxEvents = (config === null || config === void 0 ? void 0 : config.maxEvents) || DEFAULT_MAX_EVENTS; | ||
this.migrateFromLegacyStorage = config === null || config === void 0 ? void 0 : config.migrateFromLegacyStorage; | ||
this.debug = {}; | ||
@@ -20,0 +19,0 @@ if ((config === null || config === void 0 ? void 0 : config.serverEndpoint) && !validateURL(config.serverEndpoint)) { |
export const GLEAN_SCHEMA_VERSION = 1; | ||
export const GLEAN_VERSION = "1.3.0"; | ||
export const GLEAN_VERSION = "3.0.0"; | ||
export const PING_INFO_STORAGE = "glean_ping_info"; | ||
@@ -4,0 +4,0 @@ export const CLIENT_INFO_STORAGE = "glean_client_info"; |
@@ -6,7 +6,7 @@ import Dispatcher from "./dispatcher.js"; | ||
constructor() { | ||
this._initialized = false; | ||
this._testing = false; | ||
this._supportedMetrics = {}; | ||
this._startTime = new Date(); | ||
this._dispatcher = new Dispatcher(); | ||
this.initialized = false; | ||
this.testing = false; | ||
this.supportedMetrics = {}; | ||
this.startTime = new Date(); | ||
this.dispatcher = new Dispatcher(); | ||
} | ||
@@ -23,131 +23,135 @@ static get instance() { | ||
static get dispatcher() { | ||
return Context.instance._dispatcher; | ||
return Context.instance.dispatcher; | ||
} | ||
static get uploadEnabled() { | ||
if (typeof Context.instance._uploadEnabled === "undefined") { | ||
if (typeof Context.instance.uploadEnabled === "undefined") { | ||
log(LOG_TAG, [ | ||
"Attempted to access Context.uploadEnabled before it was set. This may cause unexpected behaviour.", | ||
"Attempted to access Context.uploadEnabled before it was set. This may cause unexpected behaviour." | ||
], LoggingLevel.Trace); | ||
} | ||
return Context.instance._uploadEnabled; | ||
return Context.instance.uploadEnabled; | ||
} | ||
static set uploadEnabled(upload) { | ||
Context.instance._uploadEnabled = upload; | ||
Context.instance.uploadEnabled = upload; | ||
} | ||
static get metricsDatabase() { | ||
if (typeof Context.instance._metricsDatabase === "undefined") { | ||
if (typeof Context.instance.metricsDatabase === "undefined") { | ||
log(LOG_TAG, [ | ||
"Attempted to access Context.metricsDatabase before it was set. This may cause unexpected behaviour.", | ||
"Attempted to access Context.metricsDatabase before it was set. This may cause unexpected behaviour." | ||
], LoggingLevel.Trace); | ||
} | ||
return Context.instance._metricsDatabase; | ||
return Context.instance.metricsDatabase; | ||
} | ||
static set metricsDatabase(db) { | ||
Context.instance._metricsDatabase = db; | ||
Context.instance.metricsDatabase = db; | ||
} | ||
static get eventsDatabase() { | ||
if (typeof Context.instance._eventsDatabase === "undefined") { | ||
if (typeof Context.instance.eventsDatabase === "undefined") { | ||
log(LOG_TAG, [ | ||
"Attempted to access Context.eventsDatabase before it was set. This may cause unexpected behaviour.", | ||
"Attempted to access Context.eventsDatabase before it was set. This may cause unexpected behaviour." | ||
], LoggingLevel.Trace); | ||
} | ||
return Context.instance._eventsDatabase; | ||
return Context.instance.eventsDatabase; | ||
} | ||
static set eventsDatabase(db) { | ||
Context.instance._eventsDatabase = db; | ||
Context.instance.eventsDatabase = db; | ||
} | ||
static get pingsDatabase() { | ||
if (typeof Context.instance._pingsDatabase === "undefined") { | ||
if (typeof Context.instance.pingsDatabase === "undefined") { | ||
log(LOG_TAG, [ | ||
"Attempted to access Context.pingsDatabase before it was set. This may cause unexpected behaviour.", | ||
"Attempted to access Context.pingsDatabase before it was set. This may cause unexpected behaviour." | ||
], LoggingLevel.Trace); | ||
} | ||
return Context.instance._pingsDatabase; | ||
return Context.instance.pingsDatabase; | ||
} | ||
static set pingsDatabase(db) { | ||
Context.instance._pingsDatabase = db; | ||
Context.instance.pingsDatabase = db; | ||
} | ||
static get errorManager() { | ||
if (typeof Context.instance._errorManager === "undefined") { | ||
if (typeof Context.instance.errorManager === "undefined") { | ||
log(LOG_TAG, [ | ||
"Attempted to access Context.errorManager before it was set. This may cause unexpected behaviour.", | ||
"Attempted to access Context.errorManager before it was set. This may cause unexpected behaviour." | ||
], LoggingLevel.Trace); | ||
} | ||
return Context.instance._errorManager; | ||
return Context.instance.errorManager; | ||
} | ||
static set errorManager(db) { | ||
Context.instance._errorManager = db; | ||
Context.instance.errorManager = db; | ||
} | ||
static get applicationId() { | ||
if (typeof Context.instance._applicationId === "undefined") { | ||
if (typeof Context.instance.applicationId === "undefined") { | ||
log(LOG_TAG, [ | ||
"Attempted to access Context.applicationId before it was set. This may cause unexpected behaviour.", | ||
"Attempted to access Context.applicationId before it was set. This may cause unexpected behaviour." | ||
], LoggingLevel.Trace); | ||
} | ||
return Context.instance._applicationId; | ||
return Context.instance.applicationId; | ||
} | ||
static set applicationId(id) { | ||
Context.instance._applicationId = id; | ||
Context.instance.applicationId = id; | ||
} | ||
static get initialized() { | ||
return Context.instance._initialized; | ||
return Context.instance.initialized; | ||
} | ||
static set initialized(init) { | ||
Context.instance._initialized = init; | ||
Context.instance.initialized = init; | ||
} | ||
static get config() { | ||
if (typeof Context.instance._config === "undefined") { | ||
if (typeof Context.instance.config === "undefined") { | ||
log(LOG_TAG, [ | ||
"Attempted to access Context.config before it was set. This may cause unexpected behaviour.", | ||
"Attempted to access Context.config before it was set. This may cause unexpected behaviour." | ||
], LoggingLevel.Trace); | ||
} | ||
return Context.instance._config; | ||
return Context.instance.config; | ||
} | ||
static set config(config) { | ||
Context.instance._config = config; | ||
Context.instance.config = config; | ||
} | ||
static get startTime() { | ||
return Context.instance._startTime; | ||
return Context.instance.startTime; | ||
} | ||
static get testing() { | ||
return Context.instance._testing; | ||
return Context.instance.testing; | ||
} | ||
static set testing(flag) { | ||
Context.instance._testing = flag; | ||
Context.instance.testing = flag; | ||
} | ||
static get corePings() { | ||
return Context.instance._corePings; | ||
return Context.instance.corePings; | ||
} | ||
static set corePings(pings) { | ||
Context.instance._corePings = pings; | ||
Context.instance.corePings = pings; | ||
} | ||
static get coreMetrics() { | ||
return Context.instance._coreMetrics; | ||
return Context.instance.coreMetrics; | ||
} | ||
static set coreMetrics(metrics) { | ||
Context.instance._coreMetrics = metrics; | ||
Context.instance.coreMetrics = metrics; | ||
} | ||
static set platform(platform) { | ||
Context.instance._platform = platform; | ||
Context.instance.platform = platform; | ||
} | ||
static get platform() { | ||
if (typeof Context.instance._platform === "undefined") { | ||
if (typeof Context.instance.platform === "undefined") { | ||
log(LOG_TAG, [ | ||
"Attempted to access Context.platform before it was set. This may cause unexpected behaviour.", | ||
"Attempted to access Context.platform before it was set. This may cause unexpected behaviour." | ||
], LoggingLevel.Trace); | ||
} | ||
return Context.instance._platform; | ||
return Context.instance.platform; | ||
} | ||
static isPlatformSet() { | ||
return !!Context.instance._platform; | ||
return !!Context.instance.platform; | ||
} | ||
static isPlatformSync() { | ||
var _a; | ||
return ((_a = Context.instance.platform) === null || _a === void 0 ? void 0 : _a.name) === "web"; | ||
} | ||
static getSupportedMetric(type) { | ||
return Context.instance._supportedMetrics[type]; | ||
return Context.instance.supportedMetrics[type]; | ||
} | ||
static addSupportedMetric(type, ctor) { | ||
if (type in Context.instance._supportedMetrics) { | ||
if (type in Context.instance.supportedMetrics) { | ||
return; | ||
} | ||
Context.instance._supportedMetrics[type] = ctor; | ||
Context.instance.supportedMetrics[type] = ctor; | ||
} | ||
} |
@@ -13,3 +13,3 @@ export function snapshot(hist) { | ||
values: utilizedValues, | ||
sum: hist.sum, | ||
sum: hist.sum | ||
}; | ||
@@ -27,1 +27,7 @@ } | ||
} | ||
export function getNumNegativeSamples(samples) { | ||
return samples.filter((sample) => sample < 0).length; | ||
} | ||
export function getNumTooLongSamples(samples, max) { | ||
return samples.filter((sample) => sample > max).length; | ||
} |
@@ -21,6 +21,6 @@ import { GLEAN_RESERVED_EXTRA_KEYS } from "../../constants.js"; | ||
addExtra(key, value) { | ||
if (!this._inner.extra) { | ||
this._inner.extra = {}; | ||
if (!this.inner.extra) { | ||
this.inner.extra = {}; | ||
} | ||
this._inner.extra[key] = value; | ||
this.inner.extra[key] = value; | ||
} | ||
@@ -27,0 +27,0 @@ withoutReservedExtras() { |
@@ -0,4 +1,4 @@ | ||
import { Context } from "../context.js"; | ||
import { isUndefined, testOnlyCheck } from "../utils.js"; | ||
import { getValidDynamicLabel } from "./types/labeled.js"; | ||
import { Context } from "../context.js"; | ||
import { getValidDynamicLabel, getValidDynamicLabelSync } from "./types/labeled.js"; | ||
export class MetricType { | ||
@@ -34,4 +34,13 @@ constructor(type, meta, metricCtor) { | ||
} | ||
identifierSync() { | ||
const baseIdentifier = this.baseIdentifier(); | ||
if (!isUndefined(this.dynamicLabel)) { | ||
return getValidDynamicLabelSync(this); | ||
} | ||
else { | ||
return baseIdentifier; | ||
} | ||
} | ||
shouldRecord(uploadEnabled) { | ||
return (uploadEnabled && !this.disabled); | ||
return uploadEnabled && !this.disabled; | ||
} | ||
@@ -38,0 +47,0 @@ async testGetNumRecordedErrors(errorType, ping = this.sendInPings[0]) { |
@@ -12,7 +12,3 @@ import { Context } from "../context.js"; | ||
this.type = type; | ||
try { | ||
this.name = "MetricValidationError"; | ||
} | ||
catch (_a) { | ||
} | ||
this.name = "MetricValidationError"; | ||
} | ||
@@ -22,12 +18,15 @@ async recordError(metric) { | ||
} | ||
recordErrorSync(metric) { | ||
Context.errorManager.record(metric, this.type, this.message); | ||
} | ||
} | ||
export class Metric { | ||
constructor(v) { | ||
this._inner = this.validateOrThrow(v); | ||
this.inner = this.validateOrThrow(v); | ||
} | ||
get() { | ||
return this._inner; | ||
return this.inner; | ||
} | ||
set(v) { | ||
this._inner = v; | ||
this.inner = v; | ||
} | ||
@@ -34,0 +33,0 @@ validateOrThrow(v) { |
@@ -12,3 +12,3 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
}; | ||
var _inner_1; | ||
var _inner; | ||
import { MetricType } from "../index.js"; | ||
@@ -36,3 +36,3 @@ import { Context } from "../../context.js"; | ||
payload() { | ||
return this._inner; | ||
return this.inner; | ||
} | ||
@@ -45,2 +45,10 @@ } | ||
set(value) { | ||
if (Context.isPlatformSync()) { | ||
this.setSync(value); | ||
} | ||
else { | ||
this.setAsync(value); | ||
} | ||
} | ||
setAsync(value) { | ||
Context.dispatcher.launch(async () => { | ||
@@ -61,2 +69,16 @@ if (!this.shouldRecord(Context.uploadEnabled)) { | ||
} | ||
setSync(value) { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
} | ||
try { | ||
const metric = new BooleanMetric(value); | ||
Context.metricsDatabase.record(this, metric); | ||
} | ||
catch (e) { | ||
if (e instanceof MetricValidationError) { | ||
e.recordErrorSync(this); | ||
} | ||
} | ||
} | ||
async testGetValue(ping = this.sendInPings[0]) { | ||
@@ -74,15 +96,15 @@ if (testOnlyCheck("testGetValue", LOG_TAG)) { | ||
constructor(meta) { | ||
_inner_1.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner_1, new InternalBooleanMetricType(meta), "f"); | ||
_inner.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner, new InternalBooleanMetricType(meta), "f"); | ||
} | ||
set(value) { | ||
__classPrivateFieldGet(this, _inner_1, "f").set(value); | ||
__classPrivateFieldGet(this, _inner, "f").set(value); | ||
} | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetValue(ping); | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetValue(ping); | ||
} | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetNumRecordedErrors(errorType, ping); | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetNumRecordedErrors(errorType, ping); | ||
} | ||
} | ||
_inner_1 = new WeakMap(); | ||
_inner = new WeakMap(); |
@@ -12,3 +12,3 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
}; | ||
var _inner_1; | ||
var _inner; | ||
import { saturatingAdd, isUndefined, testOnlyCheck } from "../../utils.js"; | ||
@@ -29,7 +29,7 @@ import { MetricType } from "../index.js"; | ||
payload() { | ||
return this._inner; | ||
return this.inner; | ||
} | ||
saturatingAdd(amount) { | ||
const correctAmount = this.validateOrThrow(amount); | ||
this._inner = saturatingAdd(this._inner, correctAmount); | ||
this.inner = saturatingAdd(this.inner, correctAmount); | ||
} | ||
@@ -41,2 +41,27 @@ } | ||
} | ||
add(amount) { | ||
if (Context.isPlatformSync()) { | ||
this.addSync(amount); | ||
} | ||
else { | ||
this.addAsync(amount); | ||
} | ||
} | ||
transformFn(amount) { | ||
return (v) => { | ||
const metric = new CounterMetric(amount); | ||
if (v) { | ||
try { | ||
metric.saturatingAdd(v); | ||
} | ||
catch (_a) { | ||
log(LOG_TAG, `Unexpected value found in storage for metric ${this.name}: ${JSON.stringify(v)}. Overwriting.`); | ||
} | ||
} | ||
return metric; | ||
}; | ||
} | ||
addAsync(amount) { | ||
Context.dispatcher.launch(async () => this.addUndispatched(amount)); | ||
} | ||
async addUndispatched(amount) { | ||
@@ -50,17 +75,3 @@ if (!this.shouldRecord(Context.uploadEnabled)) { | ||
try { | ||
const transformFn = ((amount) => { | ||
return (v) => { | ||
const metric = new CounterMetric(amount); | ||
if (v) { | ||
try { | ||
metric.saturatingAdd(v); | ||
} | ||
catch (_a) { | ||
log(LOG_TAG, `Unexpected value found in storage for metric ${this.name}: ${JSON.stringify(v)}. Overwriting.`); | ||
} | ||
} | ||
return metric; | ||
}; | ||
})(amount); | ||
await Context.metricsDatabase.transform(this, transformFn); | ||
await Context.metricsDatabase.transform(this, this.transformFn(amount)); | ||
} | ||
@@ -73,4 +84,17 @@ catch (e) { | ||
} | ||
add(amount) { | ||
Context.dispatcher.launch(async () => this.addUndispatched(amount)); | ||
addSync(amount) { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
} | ||
if (isUndefined(amount)) { | ||
amount = 1; | ||
} | ||
try { | ||
Context.metricsDatabase.transform(this, this.transformFn(amount)); | ||
} | ||
catch (e) { | ||
if (e instanceof MetricValidationError) { | ||
e.recordErrorSync(this); | ||
} | ||
} | ||
} | ||
@@ -89,15 +113,15 @@ async testGetValue(ping = this.sendInPings[0]) { | ||
constructor(meta) { | ||
_inner_1.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner_1, new InternalCounterMetricType(meta), "f"); | ||
_inner.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner, new InternalCounterMetricType(meta), "f"); | ||
} | ||
add(amount) { | ||
__classPrivateFieldGet(this, _inner_1, "f").add(amount); | ||
__classPrivateFieldGet(this, _inner, "f").add(amount); | ||
} | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetValue(ping); | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetValue(ping); | ||
} | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetNumRecordedErrors(errorType, ping); | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetNumRecordedErrors(errorType, ping); | ||
} | ||
} | ||
_inner_1 = new WeakMap(); | ||
_inner = new WeakMap(); |
@@ -12,3 +12,3 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
}; | ||
var _inner_1; | ||
var _inner; | ||
import { Context } from "../../context.js"; | ||
@@ -21,3 +21,3 @@ import { Metric, MetricValidation, MetricValidationError } from "../metric.js"; | ||
import { constructLinearHistogramFromValues } from "../../../histogram/linear.js"; | ||
import { extractAccumulatedValuesFromJsonValue, snapshot } from "../distributions.js"; | ||
import { extractAccumulatedValuesFromJsonValue, getNumNegativeSamples, snapshot } from "../distributions.js"; | ||
import { isUndefined, testOnlyCheck } from "../../utils.js"; | ||
@@ -30,3 +30,3 @@ const LOG_TAG = "core.metrics.CustomDistributionMetricType"; | ||
get customDistribution() { | ||
return this._inner; | ||
return this.inner; | ||
} | ||
@@ -39,3 +39,3 @@ validate(v) { | ||
errorType: ErrorType.InvalidType, | ||
errorMessage: `Expected valid CustomDistribution object, got ${JSON.stringify(obj)}`, | ||
errorMessage: `Expected valid CustomDistribution object, got ${JSON.stringify(obj)}` | ||
}; | ||
@@ -47,3 +47,3 @@ } | ||
errorType: ErrorType.InvalidValue, | ||
errorMessage: `Expected bucket count to be greater than 0, got ${obj.bucketCount}`, | ||
errorMessage: `Expected bucket count to be greater than 0, got ${obj.bucketCount}` | ||
}; | ||
@@ -55,3 +55,3 @@ } | ||
errorType: ErrorType.InvalidValue, | ||
errorMessage: `Expected histogram rangeMin to be greater than 0, got ${obj.rangeMin}`, | ||
errorMessage: `Expected histogram rangeMin to be greater than 0, got ${obj.rangeMin}` | ||
}; | ||
@@ -63,3 +63,3 @@ } | ||
errorType: ErrorType.InvalidValue, | ||
errorMessage: `Expected histogram rangeMax to be greater than 0, got ${obj.rangeMax}`, | ||
errorMessage: `Expected histogram rangeMax to be greater than 0, got ${obj.rangeMax}` | ||
}; | ||
@@ -71,15 +71,15 @@ } | ||
errorType: ErrorType.InvalidValue, | ||
errorMessage: `Expected histogram type to be either Linear or Exponential, got ${obj.histogramType}`, | ||
errorMessage: `Expected histogram type to be either Linear or Exponential, got ${obj.histogramType}` | ||
}; | ||
} | ||
return { | ||
type: MetricValidation.Success, | ||
type: MetricValidation.Success | ||
}; | ||
} | ||
payload() { | ||
const { bucketCount, histogramType, rangeMax, rangeMin, values } = this._inner; | ||
const { bucketCount, histogramType, rangeMax, rangeMin, values } = this.inner; | ||
const hist = constructHistogramByType(values, rangeMin, rangeMax, bucketCount, histogramType); | ||
return { | ||
sum: hist.sum, | ||
values: hist.values, | ||
values: hist.values | ||
}; | ||
@@ -97,2 +97,28 @@ } | ||
accumulateSamples(samples) { | ||
if (Context.isPlatformSync()) { | ||
this.setSync(samples); | ||
} | ||
else { | ||
this.setAsync(samples); | ||
} | ||
} | ||
transformFn(samples) { | ||
return (old) => { | ||
const values = extractAccumulatedValuesFromJsonValue(old); | ||
const convertedSamples = []; | ||
samples.forEach((sample) => { | ||
if (sample >= 0) { | ||
convertedSamples.push(sample); | ||
} | ||
}); | ||
return new CustomDistributionMetric({ | ||
values: [...values, ...convertedSamples], | ||
rangeMin: this.rangeMin, | ||
rangeMax: this.rangeMax, | ||
bucketCount: this.bucketCount, | ||
histogramType: this.histogramType | ||
}); | ||
}; | ||
} | ||
setAsync(samples) { | ||
Context.dispatcher.launch(async () => { | ||
@@ -102,26 +128,5 @@ if (!this.shouldRecord(Context.uploadEnabled)) { | ||
} | ||
let numNegativeSamples = 0; | ||
try { | ||
const transformFn = ((samples) => { | ||
return (old) => { | ||
const values = extractAccumulatedValuesFromJsonValue(old); | ||
const convertedSamples = []; | ||
samples.forEach((sample) => { | ||
if (sample < 0) { | ||
numNegativeSamples++; | ||
} | ||
else { | ||
convertedSamples.push(sample); | ||
} | ||
}); | ||
return new CustomDistributionMetric({ | ||
values: [...values, ...convertedSamples], | ||
rangeMin: this.rangeMin, | ||
rangeMax: this.rangeMax, | ||
bucketCount: this.bucketCount, | ||
histogramType: this.histogramType, | ||
}); | ||
}; | ||
})(samples); | ||
await Context.metricsDatabase.transform(this, transformFn); | ||
await Context.metricsDatabase.transform(this, this.transformFn(samples)); | ||
const numNegativeSamples = getNumNegativeSamples(samples); | ||
if (numNegativeSamples > 0) { | ||
@@ -138,2 +143,19 @@ await Context.errorManager.record(this, ErrorType.InvalidValue, `Accumulated ${numNegativeSamples} negative samples`, numNegativeSamples); | ||
} | ||
setSync(samples) { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
} | ||
try { | ||
Context.metricsDatabase.transform(this, this.transformFn(samples)); | ||
const numNegativeSamples = getNumNegativeSamples(samples); | ||
if (numNegativeSamples > 0) { | ||
Context.errorManager.record(this, ErrorType.InvalidValue, `Accumulated ${numNegativeSamples} negative samples`, numNegativeSamples); | ||
} | ||
} | ||
catch (e) { | ||
if (e instanceof MetricValidationError) { | ||
e.recordErrorSync(this); | ||
} | ||
} | ||
} | ||
async testGetValue(ping = this.sendInPings[0]) { | ||
@@ -154,16 +176,16 @@ if (testOnlyCheck("testGetValue", LOG_TAG)) { | ||
constructor(meta, rangeMin, rangeMax, bucketCount, histogramType) { | ||
_inner_1.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner_1, new InternalCustomDistributionMetricType(meta, rangeMin, rangeMax, bucketCount, histogramType), "f"); | ||
_inner.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner, new InternalCustomDistributionMetricType(meta, rangeMin, rangeMax, bucketCount, histogramType), "f"); | ||
} | ||
accumulateSamples(samples) { | ||
__classPrivateFieldGet(this, _inner_1, "f").accumulateSamples(samples); | ||
__classPrivateFieldGet(this, _inner, "f").accumulateSamples(samples); | ||
} | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetValue(ping); | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetValue(ping); | ||
} | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetNumRecordedErrors(errorType, ping); | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetNumRecordedErrors(errorType, ping); | ||
} | ||
} | ||
_inner_1 = new WeakMap(); | ||
_inner = new WeakMap(); | ||
function constructHistogramByType(values, rangeMin, rangeMax, bucketCount, histogramType) { | ||
@@ -170,0 +192,0 @@ switch (histogramType) { |
@@ -12,3 +12,3 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
}; | ||
var _inner_1; | ||
var _inner; | ||
import { MetricType } from "../index.js"; | ||
@@ -41,13 +41,20 @@ import TimeUnit from "../../metrics/time_unit.js"; | ||
} | ||
static fromRawDatetime(isoString, timezoneOffset, timeUnit) { | ||
return new DatetimeMetric({ | ||
timeUnit, | ||
timezone: timezoneOffset, | ||
date: isoString | ||
}); | ||
} | ||
get date() { | ||
return new Date(this._inner.date); | ||
return new Date(this.inner.date); | ||
} | ||
get timezone() { | ||
return this._inner.timezone; | ||
return this.inner.timezone; | ||
} | ||
get timeUnit() { | ||
return this._inner.timeUnit; | ||
return this.inner.timeUnit; | ||
} | ||
get dateISOString() { | ||
return this._inner.date; | ||
return this.inner.date; | ||
} | ||
@@ -61,3 +68,5 @@ validate(v) { | ||
} | ||
const timeUnitVerification = "timeUnit" in v && isString(v.timeUnit) && Object.values(TimeUnit).includes(v.timeUnit); | ||
const timeUnitVerification = "timeUnit" in v && | ||
isString(v.timeUnit) && | ||
Object.values(TimeUnit).includes(v.timeUnit); | ||
const timezoneVerification = "timezone" in v && isNumber(v.timezone); | ||
@@ -78,3 +87,3 @@ const dateVerification = "date" in v && isString(v.date) && v.date.length === 24 && !isNaN(Date.parse(v.date)); | ||
} | ||
const correctedDate = new Date(parseInt(extractedDateInfo[0]), parseInt(extractedDateInfo[1]) - 1, parseInt(extractedDateInfo[2]), parseInt(extractedDateInfo[3]) - (this.timezone / 60), parseInt(extractedDateInfo[4]), parseInt(extractedDateInfo[5]), parseInt(extractedDateInfo[6])); | ||
const correctedDate = new Date(parseInt(extractedDateInfo[0]), parseInt(extractedDateInfo[1]) - 1, parseInt(extractedDateInfo[2]), parseInt(extractedDateInfo[3]) - this.timezone / 60, parseInt(extractedDateInfo[4]), parseInt(extractedDateInfo[5]), parseInt(extractedDateInfo[6])); | ||
const timezone = formatTimezoneOffset(this.timezone); | ||
@@ -114,6 +123,11 @@ const year = correctedDate.getFullYear().toString().padStart(2, "0"); | ||
} | ||
async setUndispatched(value) { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
set(value) { | ||
if (Context.isPlatformSync()) { | ||
this.setSync(value); | ||
} | ||
else { | ||
this.setAsync(value); | ||
} | ||
} | ||
truncateDate(value) { | ||
if (!value) { | ||
@@ -124,3 +138,3 @@ value = new Date(); | ||
switch (this.timeUnit) { | ||
case (TimeUnit.Day): | ||
case TimeUnit.Day: | ||
truncatedDate.setMilliseconds(0); | ||
@@ -130,10 +144,10 @@ truncatedDate.setSeconds(0); | ||
truncatedDate.setMilliseconds(0); | ||
case (TimeUnit.Hour): | ||
case TimeUnit.Hour: | ||
truncatedDate.setMilliseconds(0); | ||
truncatedDate.setSeconds(0); | ||
truncatedDate.setMinutes(0); | ||
case (TimeUnit.Minute): | ||
case TimeUnit.Minute: | ||
truncatedDate.setMilliseconds(0); | ||
truncatedDate.setSeconds(0); | ||
case (TimeUnit.Second): | ||
case TimeUnit.Second: | ||
truncatedDate.setMilliseconds(0); | ||
@@ -143,4 +157,14 @@ default: | ||
} | ||
return truncatedDate; | ||
} | ||
setAsync(value) { | ||
Context.dispatcher.launch(() => this.setUndispatched(value)); | ||
} | ||
async setUndispatched(value) { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
} | ||
const truncatedDate = this.truncateDate(value); | ||
try { | ||
const metric = DatetimeMetric.fromDate(value, this.timeUnit); | ||
const metric = DatetimeMetric.fromDate(truncatedDate, this.timeUnit); | ||
await Context.metricsDatabase.record(this, metric); | ||
@@ -154,5 +178,31 @@ } | ||
} | ||
set(value) { | ||
Context.dispatcher.launch(() => this.setUndispatched(value)); | ||
setSync(value) { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
} | ||
const truncatedDate = this.truncateDate(value); | ||
try { | ||
const metric = DatetimeMetric.fromDate(truncatedDate, this.timeUnit); | ||
Context.metricsDatabase.record(this, metric); | ||
} | ||
catch (e) { | ||
if (e instanceof MetricValidationError) { | ||
e.recordErrorSync(this); | ||
} | ||
} | ||
} | ||
setSyncRaw(isoString, timezone, timeUnit) { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
} | ||
try { | ||
const metric = DatetimeMetric.fromRawDatetime(isoString, timezone, timeUnit); | ||
Context.metricsDatabase.record(this, metric); | ||
} | ||
catch (e) { | ||
if (e instanceof MetricValidationError) { | ||
e.recordErrorSync(this); | ||
} | ||
} | ||
} | ||
async testGetValueAsDatetimeMetric(ping, fn) { | ||
@@ -180,18 +230,18 @@ if (testOnlyCheck(fn, LOG_TAG)) { | ||
constructor(meta, timeUnit) { | ||
_inner_1.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner_1, new InternalDatetimeMetricType(meta, timeUnit), "f"); | ||
_inner.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner, new InternalDatetimeMetricType(meta, timeUnit), "f"); | ||
} | ||
set(value) { | ||
__classPrivateFieldGet(this, _inner_1, "f").set(value); | ||
__classPrivateFieldGet(this, _inner, "f").set(value); | ||
} | ||
async testGetValueAsString(ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetValueAsString(ping); | ||
async testGetValueAsString(ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetValueAsString(ping); | ||
} | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetValue(ping); | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetValue(ping); | ||
} | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetNumRecordedErrors(errorType, ping); | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetNumRecordedErrors(errorType, ping); | ||
} | ||
} | ||
_inner_1 = new WeakMap(); | ||
_inner = new WeakMap(); |
@@ -15,3 +15,3 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
import { MetricType } from "../index.js"; | ||
import { getMonotonicNow, isString, testOnlyCheck, truncateStringAtBoundaryWithError } from "../../utils.js"; | ||
import { getMonotonicNow, isString, testOnlyCheck, truncateStringAtBoundaryWithError, truncateStringAtBoundaryWithErrorSync } from "../../utils.js"; | ||
import { Context } from "../../context.js"; | ||
@@ -27,2 +27,15 @@ import { ErrorType } from "../../error/error_type.js"; | ||
} | ||
record(extra, timestamp = getMonotonicNow()) { | ||
if (Context.isPlatformSync()) { | ||
this.recordSync(timestamp, extra); | ||
} | ||
else { | ||
this.recordAsync(timestamp, extra); | ||
} | ||
} | ||
recordAsync(timestamp, extra) { | ||
Context.dispatcher.launch(async () => { | ||
await this.recordUndispatched(extra, timestamp); | ||
}); | ||
} | ||
async recordUndispatched(extra, timestamp = getMonotonicNow()) { | ||
@@ -37,3 +50,3 @@ if (!this.shouldRecord(Context.uploadEnabled)) { | ||
timestamp, | ||
extra, | ||
extra | ||
}); | ||
@@ -60,3 +73,3 @@ let truncatedExtra = undefined; | ||
...metric.get(), | ||
extra: truncatedExtra, | ||
extra: truncatedExtra | ||
}); | ||
@@ -71,7 +84,42 @@ return Context.eventsDatabase.record(this, metric); | ||
} | ||
record(extra) { | ||
const timestamp = getMonotonicNow(); | ||
Context.dispatcher.launch(async () => { | ||
await this.recordUndispatched(extra, timestamp); | ||
}); | ||
recordSync(timestamp, extra) { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
} | ||
try { | ||
const metric = new RecordedEvent({ | ||
category: this.category, | ||
name: this.name, | ||
timestamp, | ||
extra | ||
}); | ||
let truncatedExtra = undefined; | ||
if (extra && this.allowedExtraKeys) { | ||
truncatedExtra = {}; | ||
for (const [name, value] of Object.entries(extra)) { | ||
if (this.allowedExtraKeys.includes(name)) { | ||
if (isString(value)) { | ||
truncatedExtra[name] = truncateStringAtBoundaryWithErrorSync(this, value, MAX_LENGTH_EXTRA_KEY_VALUE); | ||
} | ||
else { | ||
truncatedExtra[name] = value; | ||
} | ||
} | ||
else { | ||
Context.errorManager.record(this, ErrorType.InvalidValue, `Invalid key index: ${name}`); | ||
continue; | ||
} | ||
} | ||
} | ||
metric.set({ | ||
...metric.get(), | ||
extra: truncatedExtra | ||
}); | ||
Context.eventsDatabase.record(this, metric); | ||
} | ||
catch (e) { | ||
if (e instanceof MetricValidationError) { | ||
e.recordErrorSync(this); | ||
} | ||
} | ||
} | ||
@@ -78,0 +126,0 @@ async testGetValue(ping = this.sendInPings[0]) { |
@@ -12,3 +12,3 @@ import { Metric, MetricValidation } from "../metric.js"; | ||
payload() { | ||
return this._inner; | ||
return this.inner; | ||
} | ||
@@ -52,6 +52,32 @@ } | ||
} | ||
return (hitError) | ||
? combineIdentifierAndLabel(metric.baseIdentifier(), OTHER_LABEL) | ||
: key; | ||
return hitError ? combineIdentifierAndLabel(metric.baseIdentifier(), OTHER_LABEL) : key; | ||
} | ||
export function getValidDynamicLabelSync(metric) { | ||
if (metric.dynamicLabel === undefined) { | ||
throw new Error("This point should never be reached."); | ||
} | ||
const key = combineIdentifierAndLabel(metric.baseIdentifier(), metric.dynamicLabel); | ||
for (const ping of metric.sendInPings) { | ||
if (Context.metricsDatabase.hasMetric(metric.lifetime, ping, metric.type, key)) { | ||
return key; | ||
} | ||
} | ||
let numUsedKeys = 0; | ||
for (const ping of metric.sendInPings) { | ||
numUsedKeys += Context.metricsDatabase.countByBaseIdentifier(metric.lifetime, ping, metric.type, metric.baseIdentifier()); | ||
} | ||
let hitError = false; | ||
if (numUsedKeys >= MAX_LABELS) { | ||
hitError = true; | ||
} | ||
else if (metric.dynamicLabel.length > MAX_LABEL_LENGTH) { | ||
hitError = true; | ||
Context.errorManager.record(metric, ErrorType.InvalidLabel, `Label length ${metric.dynamicLabel.length} exceeds maximum of ${MAX_LABEL_LENGTH}.`); | ||
} | ||
else if (!LABEL_REGEX.test(metric.dynamicLabel)) { | ||
hitError = true; | ||
Context.errorManager.record(metric, ErrorType.InvalidLabel, `Label must be snake_case, got '${metric.dynamicLabel}'.`); | ||
} | ||
return hitError ? combineIdentifierAndLabel(metric.baseIdentifier(), OTHER_LABEL) : key; | ||
} | ||
class LabeledMetricType { | ||
@@ -58,0 +84,0 @@ constructor(meta, submetric, labels) { |
@@ -12,3 +12,3 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
}; | ||
var _inner_1; | ||
var _inner; | ||
import { MetricType } from "../index.js"; | ||
@@ -20,3 +20,3 @@ import { Metric, MetricValidation, MetricValidationError } from "../metric.js"; | ||
import { constructFunctionalHistogramFromValues } from "../../../histogram/functional.js"; | ||
import { extractAccumulatedValuesFromJsonValue, snapshot } from "../distributions.js"; | ||
import { extractAccumulatedValuesFromJsonValue, getNumNegativeSamples, getNumTooLongSamples, snapshot } from "../distributions.js"; | ||
import { convertMemoryUnitToBytes } from "../memory_unit.js"; | ||
@@ -32,3 +32,3 @@ const LOG_TAG = "core.metrics.MemoryDistributionMetricType"; | ||
get memoryDistribution() { | ||
return this._inner; | ||
return this.inner; | ||
} | ||
@@ -40,3 +40,3 @@ validate(v) { | ||
errorType: ErrorType.InvalidType, | ||
errorMessage: `Expected valid MemoryDistribution object, got ${JSON.stringify(v)}`, | ||
errorMessage: `Expected valid MemoryDistribution object, got ${JSON.stringify(v)}` | ||
}; | ||
@@ -49,3 +49,3 @@ } | ||
errorType: ErrorType.InvalidValue, | ||
errorMessage: `Expected all samples to be greater than 0, got ${negativeSample}`, | ||
errorMessage: `Expected all samples to be greater than 0, got ${negativeSample}` | ||
}; | ||
@@ -56,6 +56,6 @@ } | ||
payload() { | ||
const hist = constructFunctionalHistogramFromValues(this._inner, LOG_BASE, BUCKETS_PER_MAGNITUDE); | ||
const hist = constructFunctionalHistogramFromValues(this.inner, LOG_BASE, BUCKETS_PER_MAGNITUDE); | ||
return { | ||
values: hist.values, | ||
sum: hist.sum, | ||
sum: hist.sum | ||
}; | ||
@@ -70,2 +70,40 @@ } | ||
accumulate(sample) { | ||
if (Context.isPlatformSync()) { | ||
this.accumulateSync(sample); | ||
} | ||
else { | ||
this.accumulateAsync(sample); | ||
} | ||
} | ||
accumulateTransformFn(sample) { | ||
return (old) => { | ||
const values = extractAccumulatedValuesFromJsonValue(old); | ||
return new MemoryDistributionMetric([...values, sample]); | ||
}; | ||
} | ||
accumulateSamples(samples) { | ||
if (Context.isPlatformSync()) { | ||
this.accumulateSamplesSync(samples); | ||
} | ||
else { | ||
this.accumulateSamplesAsync(samples); | ||
} | ||
} | ||
accumulateSamplesTransformFn(samples) { | ||
return (old) => { | ||
const values = extractAccumulatedValuesFromJsonValue(old); | ||
const convertedSamples = []; | ||
samples.forEach((sample) => { | ||
if (sample >= 0) { | ||
sample = convertMemoryUnitToBytes(sample, this.memoryUnit); | ||
if (sample > MAX_BYTES) { | ||
sample = MAX_BYTES; | ||
} | ||
convertedSamples.push(sample); | ||
} | ||
}); | ||
return new MemoryDistributionMetric([...values, ...convertedSamples]); | ||
}; | ||
} | ||
accumulateAsync(sample) { | ||
Context.dispatcher.launch(async () => { | ||
@@ -85,9 +123,3 @@ if (!this.shouldRecord(Context.uploadEnabled)) { | ||
try { | ||
const transformFn = ((sample) => { | ||
return (old) => { | ||
const values = extractAccumulatedValuesFromJsonValue(old); | ||
return new MemoryDistributionMetric([...values, sample]); | ||
}; | ||
})(convertedSample); | ||
await Context.metricsDatabase.transform(this, transformFn); | ||
await Context.metricsDatabase.transform(this, this.accumulateTransformFn(convertedSample)); | ||
} | ||
@@ -101,3 +133,3 @@ catch (e) { | ||
} | ||
accumulateSamples(samples) { | ||
accumulateSamplesAsync(samples) { | ||
Context.dispatcher.launch(async () => { | ||
@@ -107,28 +139,8 @@ if (!this.shouldRecord(Context.uploadEnabled)) { | ||
} | ||
let numNegativeSamples = 0; | ||
let numTooLongSamples = 0; | ||
const transformFn = ((samples) => { | ||
return (old) => { | ||
const values = extractAccumulatedValuesFromJsonValue(old); | ||
const convertedSamples = []; | ||
samples.forEach((sample) => { | ||
if (sample < 0) { | ||
numNegativeSamples++; | ||
} | ||
else { | ||
sample = convertMemoryUnitToBytes(sample, this.memoryUnit); | ||
if (sample > MAX_BYTES) { | ||
numTooLongSamples++; | ||
sample = MAX_BYTES; | ||
} | ||
convertedSamples.push(sample); | ||
} | ||
}); | ||
return new MemoryDistributionMetric([...values, ...convertedSamples]); | ||
}; | ||
})(samples); | ||
await Context.metricsDatabase.transform(this, transformFn); | ||
await Context.metricsDatabase.transform(this, this.accumulateSamplesTransformFn(samples)); | ||
const numNegativeSamples = getNumNegativeSamples(samples); | ||
if (numNegativeSamples > 0) { | ||
await Context.errorManager.record(this, ErrorType.InvalidValue, `Accumulated ${numNegativeSamples} negative samples`, numNegativeSamples); | ||
} | ||
const numTooLongSamples = getNumTooLongSamples(samples, MAX_BYTES); | ||
if (numTooLongSamples > 0) { | ||
@@ -139,2 +151,38 @@ await Context.errorManager.record(this, ErrorType.InvalidValue, `Accumulated ${numTooLongSamples} larger than 1TB`, numTooLongSamples); | ||
} | ||
accumulateSync(sample) { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
} | ||
if (sample < 0) { | ||
Context.errorManager.record(this, ErrorType.InvalidValue, "Accumulated a negative sample"); | ||
return; | ||
} | ||
let convertedSample = convertMemoryUnitToBytes(sample, this.memoryUnit); | ||
if (sample > MAX_BYTES) { | ||
Context.errorManager.record(this, ErrorType.InvalidValue, "Sample is bigger than 1 terabyte."); | ||
convertedSample = MAX_BYTES; | ||
} | ||
try { | ||
Context.metricsDatabase.transform(this, this.accumulateTransformFn(convertedSample)); | ||
} | ||
catch (e) { | ||
if (e instanceof MetricValidationError) { | ||
e.recordErrorSync(this); | ||
} | ||
} | ||
} | ||
accumulateSamplesSync(samples) { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
} | ||
Context.metricsDatabase.transform(this, this.accumulateSamplesTransformFn(samples)); | ||
const numNegativeSamples = getNumNegativeSamples(samples); | ||
if (numNegativeSamples > 0) { | ||
Context.errorManager.record(this, ErrorType.InvalidValue, `Accumulated ${numNegativeSamples} negative samples`, numNegativeSamples); | ||
} | ||
const numTooLongSamples = getNumTooLongSamples(samples, MAX_BYTES); | ||
if (numTooLongSamples > 0) { | ||
Context.errorManager.record(this, ErrorType.InvalidValue, `Accumulated ${numTooLongSamples} larger than 1TB`, numTooLongSamples); | ||
} | ||
} | ||
async testGetValue(ping = this.sendInPings[0]) { | ||
@@ -160,18 +208,18 @@ if (testOnlyCheck("testGetValue", LOG_TAG)) { | ||
constructor(meta, memoryUnit) { | ||
_inner_1.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner_1, new InternalMemoryDistributionMetricType(meta, memoryUnit), "f"); | ||
_inner.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner, new InternalMemoryDistributionMetricType(meta, memoryUnit), "f"); | ||
} | ||
accumulate(sample) { | ||
__classPrivateFieldGet(this, _inner_1, "f").accumulate(sample); | ||
__classPrivateFieldGet(this, _inner, "f").accumulate(sample); | ||
} | ||
accumulateSamples(samples) { | ||
__classPrivateFieldGet(this, _inner_1, "f").accumulateSamples(samples); | ||
__classPrivateFieldGet(this, _inner, "f").accumulateSamples(samples); | ||
} | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetValue(ping); | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetValue(ping); | ||
} | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetNumRecordedErrors(errorType, ping); | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetNumRecordedErrors(errorType, ping); | ||
} | ||
} | ||
_inner_1 = new WeakMap(); | ||
_inner = new WeakMap(); |
@@ -12,3 +12,3 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
}; | ||
var _inner_1; | ||
var _inner; | ||
import { MetricType } from "../index.js"; | ||
@@ -29,3 +29,3 @@ import { testOnlyCheck } from "../../utils.js"; | ||
payload() { | ||
return this._inner; | ||
return this.inner; | ||
} | ||
@@ -37,2 +37,13 @@ } | ||
} | ||
set(value) { | ||
if (Context.isPlatformSync()) { | ||
this.setSync(value); | ||
} | ||
else { | ||
this.setAsync(value); | ||
} | ||
} | ||
setAsync(value) { | ||
Context.dispatcher.launch(() => this.setUndispatched(value)); | ||
} | ||
async setUndispatched(value) { | ||
@@ -59,4 +70,22 @@ if (!this.shouldRecord(Context.uploadEnabled)) { | ||
} | ||
set(value) { | ||
Context.dispatcher.launch(() => this.setUndispatched(value)); | ||
setSync(value) { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
} | ||
if (value < 0) { | ||
Context.errorManager.record(this, ErrorType.InvalidValue, `Set negative value ${value}`); | ||
return; | ||
} | ||
if (value > Number.MAX_SAFE_INTEGER) { | ||
value = Number.MAX_SAFE_INTEGER; | ||
} | ||
try { | ||
const metric = new QuantityMetric(value); | ||
Context.metricsDatabase.record(this, metric); | ||
} | ||
catch (e) { | ||
if (e instanceof MetricValidationError) { | ||
e.recordErrorSync(this); | ||
} | ||
} | ||
} | ||
@@ -75,15 +104,15 @@ async testGetValue(ping = this.sendInPings[0]) { | ||
constructor(meta) { | ||
_inner_1.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner_1, new InternalQuantityMetricType(meta), "f"); | ||
_inner.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner, new InternalQuantityMetricType(meta), "f"); | ||
} | ||
set(value) { | ||
__classPrivateFieldGet(this, _inner_1, "f").set(value); | ||
__classPrivateFieldGet(this, _inner, "f").set(value); | ||
} | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetValue(ping); | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetValue(ping); | ||
} | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetNumRecordedErrors(errorType, ping); | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetNumRecordedErrors(errorType, ping); | ||
} | ||
} | ||
_inner_1 = new WeakMap(); | ||
_inner = new WeakMap(); |
@@ -12,3 +12,3 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
}; | ||
var _inner_1; | ||
var _inner; | ||
import { MetricType } from "../index.js"; | ||
@@ -26,6 +26,6 @@ import { Context } from "../../context.js"; | ||
get numerator() { | ||
return this._inner.numerator; | ||
return this.inner.numerator; | ||
} | ||
get denominator() { | ||
return this._inner.denominator; | ||
return this.inner.denominator; | ||
} | ||
@@ -50,3 +50,3 @@ validate(v) { | ||
payload() { | ||
return this._inner; | ||
return this.inner; | ||
} | ||
@@ -58,3 +58,41 @@ } | ||
} | ||
addToNumerator(amount) { | ||
this.add({ | ||
denominator: 0, | ||
numerator: amount | ||
}); | ||
} | ||
addToDenominator(amount) { | ||
this.add({ | ||
numerator: 0, | ||
denominator: amount | ||
}); | ||
} | ||
add(value) { | ||
if (Context.isPlatformSync()) { | ||
this.addSync(value); | ||
} | ||
else { | ||
this.addAsync(value); | ||
} | ||
} | ||
transformFn(value) { | ||
return (v) => { | ||
const metric = new RateMetric(value); | ||
if (v) { | ||
try { | ||
const persistedMetric = new RateMetric(v); | ||
metric.set({ | ||
numerator: saturatingAdd(metric.numerator, persistedMetric.numerator), | ||
denominator: saturatingAdd(metric.denominator, persistedMetric.denominator) | ||
}); | ||
} | ||
catch (_a) { | ||
log(LOG_TAG, `Unexpected value found in storage for metric ${this.name}: ${JSON.stringify(v)}. Overwriting.`); | ||
} | ||
} | ||
return metric; | ||
}; | ||
} | ||
addAsync(value) { | ||
Context.dispatcher.launch(async () => { | ||
@@ -65,21 +103,3 @@ if (!this.shouldRecord(Context.uploadEnabled)) { | ||
try { | ||
const transformFn = ((value) => { | ||
return (v) => { | ||
const metric = new RateMetric(value); | ||
if (v) { | ||
try { | ||
const persistedMetric = new RateMetric(v); | ||
metric.set({ | ||
numerator: saturatingAdd(metric.numerator, persistedMetric.numerator), | ||
denominator: saturatingAdd(metric.denominator, persistedMetric.denominator), | ||
}); | ||
} | ||
catch (_a) { | ||
log(LOG_TAG, `Unexpected value found in storage for metric ${this.name}: ${JSON.stringify(v)}. Overwriting.`); | ||
} | ||
} | ||
return metric; | ||
}; | ||
})(value); | ||
await Context.metricsDatabase.transform(this, transformFn); | ||
await Context.metricsDatabase.transform(this, this.transformFn(value)); | ||
} | ||
@@ -93,14 +113,15 @@ catch (e) { | ||
} | ||
addToNumerator(amount) { | ||
this.add({ | ||
denominator: 0, | ||
numerator: amount, | ||
}); | ||
addSync(value) { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
} | ||
try { | ||
Context.metricsDatabase.transform(this, this.transformFn(value)); | ||
} | ||
catch (e) { | ||
if (e instanceof MetricValidationError) { | ||
e.recordErrorSync(this); | ||
} | ||
} | ||
} | ||
addToDenominator(amount) { | ||
this.add({ | ||
numerator: 0, | ||
denominator: amount, | ||
}); | ||
} | ||
async testGetValue(ping = this.sendInPings[0]) { | ||
@@ -118,18 +139,18 @@ if (testOnlyCheck("testGetValue", LOG_TAG)) { | ||
constructor(meta) { | ||
_inner_1.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner_1, new InternalRateMetricType(meta), "f"); | ||
_inner.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner, new InternalRateMetricType(meta), "f"); | ||
} | ||
addToNumerator(amount) { | ||
__classPrivateFieldGet(this, _inner_1, "f").addToNumerator(amount); | ||
__classPrivateFieldGet(this, _inner, "f").addToNumerator(amount); | ||
} | ||
addToDenominator(amount) { | ||
__classPrivateFieldGet(this, _inner_1, "f").addToDenominator(amount); | ||
__classPrivateFieldGet(this, _inner, "f").addToDenominator(amount); | ||
} | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetValue(ping); | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetValue(ping); | ||
} | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetNumRecordedErrors(errorType, ping); | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetNumRecordedErrors(errorType, ping); | ||
} | ||
} | ||
_inner_1 = new WeakMap(); | ||
_inner = new WeakMap(); |
@@ -12,7 +12,7 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
}; | ||
var _inner_1; | ||
var _inner; | ||
import { MetricType } from "../index.js"; | ||
import { Context } from "../../context.js"; | ||
import { Metric, MetricValidation, MetricValidationError } from "../metric.js"; | ||
import { testOnlyCheck, truncateStringAtBoundaryWithError } from "../../utils.js"; | ||
import { testOnlyCheck, truncateStringAtBoundaryWithError, truncateStringAtBoundaryWithErrorSync } from "../../utils.js"; | ||
import { ErrorType } from "../../error/error_type.js"; | ||
@@ -45,10 +45,10 @@ import log from "../../log.js"; | ||
const correctedList = this.validateOrThrow(list); | ||
const result = [...this._inner, ...correctedList]; | ||
const result = [...this.inner, ...correctedList]; | ||
if (result.length > MAX_LIST_LENGTH) { | ||
throw new MetricValidationError(`String list length of ${result.length} would exceed maximum of ${MAX_LIST_LENGTH}.`, ErrorType.InvalidValue); | ||
} | ||
this._inner = result; | ||
this.inner = result; | ||
} | ||
payload() { | ||
return this._inner; | ||
return this.inner; | ||
} | ||
@@ -61,2 +61,35 @@ } | ||
set(value) { | ||
if (Context.isPlatformSync()) { | ||
this.setSync(value); | ||
} | ||
else { | ||
this.setAsync(value); | ||
} | ||
} | ||
add(value) { | ||
if (Context.isPlatformSync()) { | ||
this.addSync(value); | ||
} | ||
else { | ||
this.addAsync(value); | ||
} | ||
} | ||
addTransformFn(value) { | ||
return (v) => { | ||
const metric = new StringListMetric([value]); | ||
try { | ||
v && metric.concat(v); | ||
} | ||
catch (e) { | ||
if (e instanceof MetricValidationError && e.type !== ErrorType.InvalidType) { | ||
throw e; | ||
} | ||
else { | ||
log(LOG_TAG, `Unexpected value found in storage for metric ${this.name}: ${JSON.stringify(v)}. Overwriting.`); | ||
} | ||
} | ||
return metric; | ||
}; | ||
} | ||
setAsync(value) { | ||
Context.dispatcher.launch(async () => { | ||
@@ -86,3 +119,3 @@ if (!this.shouldRecord(Context.uploadEnabled)) { | ||
} | ||
add(value) { | ||
addAsync(value) { | ||
Context.dispatcher.launch(async () => { | ||
@@ -94,20 +127,3 @@ if (!this.shouldRecord(Context.uploadEnabled)) { | ||
const truncatedValue = await truncateStringAtBoundaryWithError(this, value, MAX_STRING_LENGTH); | ||
const transformFn = ((value) => { | ||
return (v) => { | ||
const metric = new StringListMetric([value]); | ||
try { | ||
v && metric.concat(v); | ||
} | ||
catch (e) { | ||
if (e instanceof MetricValidationError && e.type !== ErrorType.InvalidType) { | ||
throw e; | ||
} | ||
else { | ||
log(LOG_TAG, `Unexpected value found in storage for metric ${this.name}: ${JSON.stringify(v)}. Overwriting.`); | ||
} | ||
} | ||
return metric; | ||
}; | ||
})(truncatedValue); | ||
await Context.metricsDatabase.transform(this, transformFn); | ||
await Context.metricsDatabase.transform(this, this.addTransformFn(truncatedValue)); | ||
} | ||
@@ -121,2 +137,39 @@ catch (e) { | ||
} | ||
setSync(value) { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
} | ||
try { | ||
if (value.length > MAX_LIST_LENGTH) { | ||
Context.errorManager.record(this, ErrorType.InvalidValue, `String list length of ${value.length} exceeds maximum of ${MAX_LIST_LENGTH}.`); | ||
} | ||
const metric = new StringListMetric(value); | ||
const truncatedList = []; | ||
for (let i = 0; i < Math.min(value.length, MAX_LIST_LENGTH); ++i) { | ||
const truncatedString = truncateStringAtBoundaryWithErrorSync(this, value[i], MAX_STRING_LENGTH); | ||
truncatedList.push(truncatedString); | ||
} | ||
metric.set(truncatedList); | ||
Context.metricsDatabase.record(this, metric); | ||
} | ||
catch (e) { | ||
if (e instanceof MetricValidationError) { | ||
e.recordErrorSync(this); | ||
} | ||
} | ||
} | ||
addSync(value) { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
} | ||
try { | ||
const truncatedValue = truncateStringAtBoundaryWithErrorSync(this, value, MAX_STRING_LENGTH); | ||
Context.metricsDatabase.transform(this, this.addTransformFn(truncatedValue)); | ||
} | ||
catch (e) { | ||
if (e instanceof MetricValidationError) { | ||
e.recordErrorSync(this); | ||
} | ||
} | ||
} | ||
async testGetValue(ping = this.sendInPings[0]) { | ||
@@ -134,18 +187,18 @@ if (testOnlyCheck("testGetValue", LOG_TAG)) { | ||
constructor(meta) { | ||
_inner_1.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner_1, new InternalStringListMetricType(meta), "f"); | ||
_inner.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner, new InternalStringListMetricType(meta), "f"); | ||
} | ||
set(value) { | ||
__classPrivateFieldGet(this, _inner_1, "f").set(value); | ||
__classPrivateFieldGet(this, _inner, "f").set(value); | ||
} | ||
add(value) { | ||
__classPrivateFieldGet(this, _inner_1, "f").add(value); | ||
__classPrivateFieldGet(this, _inner, "f").add(value); | ||
} | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetValue(ping); | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetValue(ping); | ||
} | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetNumRecordedErrors(errorType, ping); | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetNumRecordedErrors(errorType, ping); | ||
} | ||
} | ||
_inner_1 = new WeakMap(); | ||
_inner = new WeakMap(); |
@@ -12,7 +12,7 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
}; | ||
var _inner_1; | ||
var _inner; | ||
import { MetricType } from "../index.js"; | ||
import { Context } from "../../context.js"; | ||
import { Metric, MetricValidationError } from "../metric.js"; | ||
import { testOnlyCheck, truncateStringAtBoundaryWithError } from "../../utils.js"; | ||
import { testOnlyCheck, truncateStringAtBoundaryWithError, truncateStringAtBoundaryWithErrorSync } from "../../utils.js"; | ||
import { validateString } from "../utils.js"; | ||
@@ -29,3 +29,3 @@ const LOG_TAG = "core.metrics.StringMetricType"; | ||
payload() { | ||
return this._inner; | ||
return this.inner; | ||
} | ||
@@ -37,2 +37,13 @@ } | ||
} | ||
set(value) { | ||
if (Context.isPlatformSync()) { | ||
this.setSync(value); | ||
} | ||
else { | ||
this.setAsync(value); | ||
} | ||
} | ||
setAsync(value) { | ||
Context.dispatcher.launch(() => this.setUndispatched(value)); | ||
} | ||
async setUndispatched(value) { | ||
@@ -53,4 +64,16 @@ if (!this.shouldRecord(Context.uploadEnabled)) { | ||
} | ||
set(value) { | ||
Context.dispatcher.launch(() => this.setUndispatched(value)); | ||
setSync(value) { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
} | ||
try { | ||
const truncatedValue = truncateStringAtBoundaryWithErrorSync(this, value, MAX_LENGTH_VALUE); | ||
const metric = new StringMetric(truncatedValue); | ||
Context.metricsDatabase.record(this, metric); | ||
} | ||
catch (e) { | ||
if (e instanceof MetricValidationError) { | ||
e.recordErrorSync(this); | ||
} | ||
} | ||
} | ||
@@ -69,15 +92,15 @@ async testGetValue(ping = this.sendInPings[0]) { | ||
constructor(meta) { | ||
_inner_1.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner_1, new InternalStringMetricType(meta), "f"); | ||
_inner.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner, new InternalStringMetricType(meta), "f"); | ||
} | ||
set(value) { | ||
__classPrivateFieldGet(this, _inner_1, "f").set(value); | ||
__classPrivateFieldGet(this, _inner, "f").set(value); | ||
} | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetValue(ping); | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetValue(ping); | ||
} | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetNumRecordedErrors(errorType, ping); | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetNumRecordedErrors(errorType, ping); | ||
} | ||
} | ||
_inner_1 = new WeakMap(); | ||
_inner = new WeakMap(); |
@@ -12,4 +12,4 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
}; | ||
var _inner_1; | ||
import { testOnlyCheck, truncateStringAtBoundaryWithError } from "../../utils.js"; | ||
var _inner; | ||
import { testOnlyCheck, truncateStringAtBoundaryWithError, truncateStringAtBoundaryWithErrorSync } from "../../utils.js"; | ||
import { MetricType } from "../index.js"; | ||
@@ -30,3 +30,3 @@ import { Context } from "../../context.js"; | ||
payload() { | ||
return this._inner; | ||
return this.inner; | ||
} | ||
@@ -39,2 +39,10 @@ } | ||
set(text) { | ||
if (Context.isPlatformSync()) { | ||
this.setSync(text); | ||
} | ||
else { | ||
this.setAsync(text); | ||
} | ||
} | ||
setAsync(text) { | ||
Context.dispatcher.launch(async () => { | ||
@@ -56,2 +64,17 @@ if (!this.shouldRecord(Context.uploadEnabled)) { | ||
} | ||
setSync(text) { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
} | ||
try { | ||
const truncatedValue = truncateStringAtBoundaryWithErrorSync(this, text, TEXT_MAX_LENGTH); | ||
const metric = new TextMetric(truncatedValue); | ||
Context.metricsDatabase.record(this, metric); | ||
} | ||
catch (e) { | ||
if (e instanceof MetricValidationError) { | ||
e.recordErrorSync(this); | ||
} | ||
} | ||
} | ||
async testGetValue(ping = this.sendInPings[0]) { | ||
@@ -69,15 +92,15 @@ if (testOnlyCheck("testGetValue", LOG_TAG)) { | ||
constructor(meta) { | ||
_inner_1.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner_1, new InternalTextMetricType(meta), "f"); | ||
_inner.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner, new InternalTextMetricType(meta), "f"); | ||
} | ||
set(text) { | ||
__classPrivateFieldGet(this, _inner_1, "f").set(text); | ||
__classPrivateFieldGet(this, _inner, "f").set(text); | ||
} | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetValue(ping); | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetValue(ping); | ||
} | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetNumRecordedErrors(errorType, ping); | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetNumRecordedErrors(errorType, ping); | ||
} | ||
} | ||
_inner_1 = new WeakMap(); | ||
_inner = new WeakMap(); |
@@ -12,3 +12,3 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
}; | ||
var _inner_1; | ||
var _inner; | ||
import { isInteger } from "../../utils.js"; | ||
@@ -28,17 +28,17 @@ import TimeUnit from "../time_unit.js"; | ||
get timespan() { | ||
switch (this._inner.timeUnit) { | ||
switch (this.inner.timeUnit) { | ||
case TimeUnit.Nanosecond: | ||
return this._inner.timespan * 10 ** 6; | ||
return this.inner.timespan * 10 ** 6; | ||
case TimeUnit.Microsecond: | ||
return this._inner.timespan * 10 ** 3; | ||
return this.inner.timespan * 10 ** 3; | ||
case TimeUnit.Millisecond: | ||
return this._inner.timespan; | ||
return this.inner.timespan; | ||
case TimeUnit.Second: | ||
return Math.round(this._inner.timespan / 1000); | ||
return Math.round(this.inner.timespan / 1000); | ||
case TimeUnit.Minute: | ||
return Math.round(this._inner.timespan / 1000 / 60); | ||
return Math.round(this.inner.timespan / 1000 / 60); | ||
case TimeUnit.Hour: | ||
return Math.round(this._inner.timespan / 1000 / 60 / 60); | ||
return Math.round(this.inner.timespan / 1000 / 60 / 60); | ||
case TimeUnit.Day: | ||
return Math.round(this._inner.timespan / 1000 / 60 / 60 / 24); | ||
return Math.round(this.inner.timespan / 1000 / 60 / 60 / 24); | ||
} | ||
@@ -73,3 +73,5 @@ } | ||
} | ||
const timeUnitVerification = "timeUnit" in v && isString(v.timeUnit) && Object.values(TimeUnit).includes(v.timeUnit); | ||
const timeUnitVerification = "timeUnit" in v && | ||
isString(v.timeUnit) && | ||
Object.values(TimeUnit).includes(v.timeUnit); | ||
if (!timeUnitVerification) { | ||
@@ -85,3 +87,3 @@ return { | ||
return { | ||
time_unit: this._inner.timeUnit, | ||
time_unit: this.inner.timeUnit, | ||
value: this.timespan | ||
@@ -96,40 +98,35 @@ }; | ||
} | ||
async setRawUndispatched(elapsed) { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
start() { | ||
if (Context.isPlatformSync()) { | ||
this.startSync(); | ||
} | ||
if (!isUndefined(this.startTime)) { | ||
await Context.errorManager.record(this, ErrorType.InvalidState, "Timespan already running. Raw value not recorded."); | ||
return; | ||
else { | ||
this.startAsync(); | ||
} | ||
let reportValueExists = false; | ||
try { | ||
const transformFn = ((elapsed) => { | ||
return (old) => { | ||
let metric; | ||
try { | ||
metric = new TimespanMetric(old); | ||
reportValueExists = true; | ||
} | ||
catch (_a) { | ||
metric = new TimespanMetric({ | ||
timespan: elapsed, | ||
timeUnit: this.timeUnit, | ||
}); | ||
} | ||
return metric; | ||
}; | ||
})(elapsed); | ||
await Context.metricsDatabase.transform(this, transformFn); | ||
} | ||
stop() { | ||
if (Context.isPlatformSync()) { | ||
this.stopSync(); | ||
} | ||
catch (e) { | ||
if (e instanceof MetricValidationError) { | ||
await e.recordError(this); | ||
} | ||
else { | ||
this.stopAsync(); | ||
} | ||
if (reportValueExists) { | ||
await Context.errorManager.record(this, ErrorType.InvalidState, "Timespan value already recorded. New value discarded."); | ||
} | ||
cancel() { | ||
if (Context.isPlatformSync()) { | ||
this.cancelSync(); | ||
} | ||
else { | ||
this.cancelAsync(); | ||
} | ||
} | ||
start() { | ||
setRawNanos(elapsed) { | ||
if (Context.isPlatformSync()) { | ||
this.setRawNanosSync(elapsed); | ||
} | ||
else { | ||
this.setRawNanosAsync(elapsed); | ||
} | ||
} | ||
startAsync() { | ||
const startTime = getMonotonicNow(); | ||
@@ -148,3 +145,3 @@ Context.dispatcher.launch(async () => { | ||
} | ||
stop() { | ||
stopAsync() { | ||
const stopTime = getMonotonicNow(); | ||
@@ -169,3 +166,3 @@ Context.dispatcher.launch(async () => { | ||
} | ||
cancel() { | ||
cancelAsync() { | ||
Context.dispatcher.launch(() => { | ||
@@ -176,8 +173,121 @@ this.startTime = undefined; | ||
} | ||
setRawNanos(elapsed) { | ||
setRawNanosAsync(elapsed) { | ||
Context.dispatcher.launch(async () => { | ||
const elapsedMillis = elapsed * 10 ** (-6); | ||
const elapsedMillis = elapsed * 10 ** -6; | ||
await this.setRawUndispatched(elapsedMillis); | ||
}); | ||
} | ||
async setRawUndispatched(elapsed) { | ||
await this.setRawAsync(elapsed); | ||
} | ||
async setRawAsync(elapsed) { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
} | ||
if (!isUndefined(this.startTime)) { | ||
await Context.errorManager.record(this, ErrorType.InvalidState, "Timespan already running. Raw value not recorded."); | ||
return; | ||
} | ||
let reportValueExists = false; | ||
try { | ||
const transformFn = ((elapsed) => { | ||
return (old) => { | ||
let metric; | ||
try { | ||
metric = new TimespanMetric(old); | ||
reportValueExists = true; | ||
} | ||
catch (_a) { | ||
metric = new TimespanMetric({ | ||
timespan: elapsed, | ||
timeUnit: this.timeUnit | ||
}); | ||
} | ||
return metric; | ||
}; | ||
})(elapsed); | ||
await Context.metricsDatabase.transform(this, transformFn); | ||
} | ||
catch (e) { | ||
if (e instanceof MetricValidationError) { | ||
await e.recordError(this); | ||
} | ||
} | ||
if (reportValueExists) { | ||
await Context.errorManager.record(this, ErrorType.InvalidState, "Timespan value already recorded. New value discarded."); | ||
} | ||
} | ||
startSync() { | ||
const startTime = getMonotonicNow(); | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
} | ||
if (!isUndefined(this.startTime)) { | ||
Context.errorManager.record(this, ErrorType.InvalidState, "Timespan already started"); | ||
return; | ||
} | ||
this.startTime = startTime; | ||
} | ||
stopSync() { | ||
const stopTime = getMonotonicNow(); | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
this.startTime = undefined; | ||
return; | ||
} | ||
if (isUndefined(this.startTime)) { | ||
Context.errorManager.record(this, ErrorType.InvalidState, "Timespan not running."); | ||
return; | ||
} | ||
const elapsed = stopTime - this.startTime; | ||
this.startTime = undefined; | ||
if (elapsed < 0) { | ||
Context.errorManager.record(this, ErrorType.InvalidState, "Timespan was negative."); | ||
return; | ||
} | ||
this.setRawSync(elapsed); | ||
} | ||
cancelSync() { | ||
this.startTime = undefined; | ||
} | ||
setRawNanosSync(elapsed) { | ||
const elapsedMillis = elapsed * 10 ** -6; | ||
this.setRawSync(elapsedMillis); | ||
} | ||
setRawSync(elapsed) { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
} | ||
if (!isUndefined(this.startTime)) { | ||
Context.errorManager.record(this, ErrorType.InvalidState, "Timespan already running. Raw value not recorded."); | ||
return; | ||
} | ||
let reportValueExists = false; | ||
try { | ||
const transformFn = ((elapsed) => { | ||
return (old) => { | ||
let metric; | ||
try { | ||
metric = new TimespanMetric(old); | ||
reportValueExists = true; | ||
} | ||
catch (_a) { | ||
metric = new TimespanMetric({ | ||
timespan: elapsed, | ||
timeUnit: this.timeUnit | ||
}); | ||
} | ||
return metric; | ||
}; | ||
})(elapsed); | ||
Context.metricsDatabase.transform(this, transformFn); | ||
} | ||
catch (e) { | ||
if (e instanceof MetricValidationError) { | ||
e.recordErrorSync(this); | ||
} | ||
} | ||
if (reportValueExists) { | ||
Context.errorManager.record(this, ErrorType.InvalidState, "Timespan value already recorded. New value discarded."); | ||
} | ||
} | ||
async testGetValue(ping = this.sendInPings[0]) { | ||
@@ -190,3 +300,3 @@ if (testOnlyCheck("testGetValue", LOG_TAG)) { | ||
if (value) { | ||
return (new TimespanMetric(value)).timespan; | ||
return new TimespanMetric(value).timespan; | ||
} | ||
@@ -198,24 +308,24 @@ } | ||
constructor(meta, timeUnit) { | ||
_inner_1.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner_1, new InternalTimespanMetricType(meta, timeUnit), "f"); | ||
_inner.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner, new InternalTimespanMetricType(meta, timeUnit), "f"); | ||
} | ||
start() { | ||
__classPrivateFieldGet(this, _inner_1, "f").start(); | ||
__classPrivateFieldGet(this, _inner, "f").start(); | ||
} | ||
stop() { | ||
__classPrivateFieldGet(this, _inner_1, "f").stop(); | ||
__classPrivateFieldGet(this, _inner, "f").stop(); | ||
} | ||
cancel() { | ||
__classPrivateFieldGet(this, _inner_1, "f").cancel(); | ||
__classPrivateFieldGet(this, _inner, "f").cancel(); | ||
} | ||
setRawNanos(elapsed) { | ||
__classPrivateFieldGet(this, _inner_1, "f").setRawNanos(elapsed); | ||
__classPrivateFieldGet(this, _inner, "f").setRawNanos(elapsed); | ||
} | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetValue(ping); | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetValue(ping); | ||
} | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetNumRecordedErrors(errorType, ping); | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetNumRecordedErrors(errorType, ping); | ||
} | ||
} | ||
_inner_1 = new WeakMap(); | ||
_inner = new WeakMap(); |
@@ -12,3 +12,3 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
}; | ||
var _inner_1; | ||
var _inner; | ||
import { MetricType } from "../index.js"; | ||
@@ -22,3 +22,3 @@ import { Context } from "../../context.js"; | ||
import { snapshot } from "../distributions.js"; | ||
import { extractAccumulatedValuesFromJsonValue } from "../distributions.js"; | ||
import { extractAccumulatedValuesFromJsonValue, getNumNegativeSamples, getNumTooLongSamples } from "../distributions.js"; | ||
const LOG_TAG = "core.metrics.TimingDistributionMetricType"; | ||
@@ -33,3 +33,3 @@ const LOG_BASE = 2.0; | ||
get timingDistribution() { | ||
return this._inner; | ||
return this.inner; | ||
} | ||
@@ -41,3 +41,3 @@ validate(v) { | ||
errorType: ErrorType.InvalidType, | ||
errorMessage: `Expected valid TimingDistribution object, got ${JSON.stringify(v)}`, | ||
errorMessage: `Expected valid TimingDistribution object, got ${JSON.stringify(v)}` | ||
}; | ||
@@ -50,3 +50,3 @@ } | ||
errorType: ErrorType.InvalidValue, | ||
errorMessage: `Expected all durations to be greater than 0, got ${negativeDuration}`, | ||
errorMessage: `Expected all durations to be greater than 0, got ${negativeDuration}` | ||
}; | ||
@@ -57,6 +57,6 @@ } | ||
payload() { | ||
const hist = constructFunctionalHistogramFromValues(this._inner, LOG_BASE, BUCKETS_PER_MAGNITUDE); | ||
const hist = constructFunctionalHistogramFromValues(this.inner, LOG_BASE, BUCKETS_PER_MAGNITUDE); | ||
return { | ||
values: hist.values, | ||
sum: hist.sum, | ||
sum: hist.sum | ||
}; | ||
@@ -79,17 +79,97 @@ } | ||
const id = this.getNextTimerId(); | ||
this.setStart(id, startTime); | ||
if (Context.isPlatformSync()) { | ||
this.setStartSync(id, startTime); | ||
} | ||
else { | ||
this.setStart(id, startTime); | ||
} | ||
return id; | ||
} | ||
setStart(id, startTime) { | ||
Context.dispatcher.launch(async () => { | ||
this.startTimes[id] = startTime; | ||
return Promise.resolve(); | ||
}); | ||
this.setStartAsync(id, startTime); | ||
} | ||
stopAndAccumulate(id) { | ||
const stopTime = getCurrentTimeInNanoSeconds(); | ||
this.setStopAndAccumulate(id, stopTime); | ||
if (Context.isPlatformSync()) { | ||
this.setStopAndAccumulateSync(id, stopTime); | ||
} | ||
else { | ||
this.setStopAndAccumulate(id, stopTime); | ||
} | ||
} | ||
setStopAndAccumulate(id, stopTime) { | ||
this.setStopAndAccumulateAsync(id, stopTime); | ||
} | ||
cancel(id) { | ||
delete this.startTimes[id]; | ||
} | ||
accumulateSamples(samples) { | ||
if (Context.isPlatformSync()) { | ||
this.setAccumulateSamplesSync(samples); | ||
} | ||
else { | ||
this.setAccumulateSamples(samples); | ||
} | ||
} | ||
setAccumulateSamples(samples) { | ||
this.setAccumulateSamplesAsync(samples); | ||
} | ||
accumulateRawSamplesNanos(samples) { | ||
if (Context.isPlatformSync()) { | ||
this.accumulateRawSamplesNanosSync(samples); | ||
} | ||
else { | ||
this.accumulateRawSamplesNanosAsync(samples); | ||
} | ||
} | ||
setStopAndAccumulateTransformFn(duration) { | ||
return (old) => { | ||
const values = extractAccumulatedValuesFromJsonValue(old); | ||
return new TimingDistributionMetric([...values, duration]); | ||
}; | ||
} | ||
setAccumulateSamplesTransformFn(samples, maxSampleTime) { | ||
return (old) => { | ||
const values = extractAccumulatedValuesFromJsonValue(old); | ||
const convertedSamples = []; | ||
samples.forEach((sample) => { | ||
if (sample >= 0) { | ||
if (sample === 0) { | ||
sample = 1; | ||
} | ||
else if (sample > maxSampleTime) { | ||
sample = maxSampleTime; | ||
} | ||
sample = convertTimeUnitToNanos(sample, this.timeUnit); | ||
convertedSamples.push(sample); | ||
} | ||
}); | ||
return new TimingDistributionMetric([...values, ...convertedSamples]); | ||
}; | ||
} | ||
accumulateRawSamplesNanosTransformFn(samples, maxSampleTime) { | ||
const minSampleTime = convertTimeUnitToNanos(1, this.timeUnit); | ||
return (old) => { | ||
const values = extractAccumulatedValuesFromJsonValue(old); | ||
const convertedSamples = []; | ||
samples.forEach((sample) => { | ||
if (sample < minSampleTime) { | ||
sample = minSampleTime; | ||
} | ||
else if (sample > maxSampleTime) { | ||
sample = maxSampleTime; | ||
} | ||
convertedSamples.push(sample); | ||
}); | ||
return new TimingDistributionMetric([...values, ...convertedSamples]); | ||
}; | ||
} | ||
setStartAsync(id, startTime) { | ||
Context.dispatcher.launch(async () => { | ||
this.startTimes[id] = startTime; | ||
return Promise.resolve(); | ||
}); | ||
} | ||
setStopAndAccumulateAsync(id, stopTime) { | ||
Context.dispatcher.launch(async () => { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
@@ -99,3 +179,2 @@ delete this.startTimes[id]; | ||
} | ||
let duration; | ||
const startTime = this.startTimes[id]; | ||
@@ -109,3 +188,3 @@ if (startTime !== undefined) { | ||
} | ||
duration = stopTime - startTime; | ||
let duration = stopTime - startTime; | ||
if (duration < 0) { | ||
@@ -121,17 +200,7 @@ await Context.errorManager.record(this, ErrorType.InvalidValue, "Timer stopped with negative duration"); | ||
else if (duration > maxSampleTime) { | ||
await Context.errorManager | ||
.record(this, ErrorType.InvalidState, `Sample is longer than the max for a timeUnit of ${this.timeUnit} (${duration} ns)`) | ||
.catch(); | ||
await Context.errorManager.record(this, ErrorType.InvalidState, `Sample is longer than the max for a timeUnit of ${this.timeUnit} (${duration} ns)`); | ||
duration = maxSampleTime; | ||
} | ||
else { | ||
} | ||
try { | ||
const transformFn = ((duration) => { | ||
return (old) => { | ||
const values = extractAccumulatedValuesFromJsonValue(old); | ||
return new TimingDistributionMetric([...values, duration]); | ||
}; | ||
})(duration); | ||
await Context.metricsDatabase.transform(this, transformFn); | ||
await Context.metricsDatabase.transform(this, this.setStopAndAccumulateTransformFn(duration)); | ||
} | ||
@@ -146,9 +215,3 @@ catch (e) { | ||
} | ||
cancel(id) { | ||
delete this.startTimes[id]; | ||
} | ||
accumulateSamples(samples) { | ||
this.setAccumulateSamples(samples); | ||
} | ||
setAccumulateSamples(samples) { | ||
setAccumulateSamplesAsync(samples) { | ||
Context.dispatcher.launch(async () => { | ||
@@ -158,32 +221,9 @@ if (!this.shouldRecord(Context.uploadEnabled)) { | ||
} | ||
let numNegativeSamples = 0; | ||
let numTooLongSamples = 0; | ||
const maxSampleTime = convertTimeUnitToNanos(MAX_SAMPLE_TIME, this.timeUnit); | ||
const transformFn = ((samples) => { | ||
return (old) => { | ||
const values = extractAccumulatedValuesFromJsonValue(old); | ||
const convertedSamples = []; | ||
samples.forEach((sample) => { | ||
if (sample < 0) { | ||
numNegativeSamples++; | ||
} | ||
else { | ||
if (sample === 0) { | ||
sample = 1; | ||
} | ||
else if (sample > maxSampleTime) { | ||
numTooLongSamples++; | ||
sample = maxSampleTime; | ||
} | ||
sample = convertTimeUnitToNanos(sample, this.timeUnit); | ||
convertedSamples.push(sample); | ||
} | ||
}); | ||
return new TimingDistributionMetric([...values, ...convertedSamples]); | ||
}; | ||
})(samples); | ||
await Context.metricsDatabase.transform(this, transformFn); | ||
await Context.metricsDatabase.transform(this, this.setAccumulateSamplesTransformFn(samples, maxSampleTime)); | ||
const numNegativeSamples = getNumNegativeSamples(samples); | ||
if (numNegativeSamples > 0) { | ||
await Context.errorManager.record(this, ErrorType.InvalidValue, `Accumulated ${numNegativeSamples} negative samples`, numNegativeSamples); | ||
} | ||
const numTooLongSamples = getNumTooLongSamples(samples, maxSampleTime); | ||
if (numTooLongSamples > 0) { | ||
@@ -194,3 +234,3 @@ await Context.errorManager.record(this, ErrorType.InvalidOverflow, `${numTooLongSamples} samples are longer than the maximum of ${maxSampleTime}`, numTooLongSamples); | ||
} | ||
accumulateRawSamplesNanos(samples) { | ||
accumulateRawSamplesNanosAsync(samples) { | ||
Context.dispatcher.launch(async () => { | ||
@@ -200,23 +240,5 @@ if (!this.shouldRecord(Context.uploadEnabled)) { | ||
} | ||
let numTooLongSamples = 0; | ||
const minSampleTime = convertTimeUnitToNanos(1, this.timeUnit); | ||
const maxSampleTime = convertTimeUnitToNanos(MAX_SAMPLE_TIME, this.timeUnit); | ||
const transformFn = ((samples) => { | ||
return (old) => { | ||
const values = extractAccumulatedValuesFromJsonValue(old); | ||
const convertedSamples = []; | ||
samples.forEach((sample) => { | ||
if (sample < minSampleTime) { | ||
sample = minSampleTime; | ||
} | ||
else if (sample > maxSampleTime) { | ||
numTooLongSamples++; | ||
sample = maxSampleTime; | ||
} | ||
convertedSamples.push(sample); | ||
}); | ||
return new TimingDistributionMetric([...values, ...convertedSamples]); | ||
}; | ||
})(samples); | ||
await Context.metricsDatabase.transform(this, transformFn); | ||
await Context.metricsDatabase.transform(this, this.accumulateRawSamplesNanosTransformFn(samples, maxSampleTime)); | ||
const numTooLongSamples = getNumTooLongSamples(samples, maxSampleTime); | ||
if (numTooLongSamples > 0) { | ||
@@ -227,2 +249,67 @@ await Context.errorManager.record(this, ErrorType.InvalidOverflow, `${numTooLongSamples} samples are longer than the maximum of ${maxSampleTime}`, numTooLongSamples); | ||
} | ||
setStartSync(id, startTime) { | ||
this.startTimes[id] = startTime; | ||
} | ||
setStopAndAccumulateSync(id, stopTime) { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
delete this.startTimes[id]; | ||
return; | ||
} | ||
const startTime = this.startTimes[id]; | ||
if (startTime !== undefined) { | ||
delete this.startTimes[id]; | ||
} | ||
else { | ||
Context.errorManager.record(this, ErrorType.InvalidState, "Timing not running"); | ||
return; | ||
} | ||
let duration = stopTime - startTime; | ||
if (duration < 0) { | ||
Context.errorManager.record(this, ErrorType.InvalidValue, "Timer stopped with negative duration"); | ||
return; | ||
} | ||
const minSampleTime = convertTimeUnitToNanos(1, this.timeUnit); | ||
const maxSampleTime = convertTimeUnitToNanos(MAX_SAMPLE_TIME, this.timeUnit); | ||
if (duration < minSampleTime) { | ||
duration = minSampleTime; | ||
} | ||
else if (duration > maxSampleTime) { | ||
Context.errorManager.record(this, ErrorType.InvalidState, `Sample is longer than the max for a timeUnit of ${this.timeUnit} (${duration} ns)`); | ||
duration = maxSampleTime; | ||
} | ||
try { | ||
Context.metricsDatabase.transform(this, this.setStopAndAccumulateTransformFn(duration)); | ||
} | ||
catch (e) { | ||
if (e instanceof MetricValidationError) { | ||
e.recordErrorSync(this); | ||
} | ||
} | ||
} | ||
setAccumulateSamplesSync(samples) { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
} | ||
const maxSampleTime = convertTimeUnitToNanos(MAX_SAMPLE_TIME, this.timeUnit); | ||
Context.metricsDatabase.transform(this, this.setAccumulateSamplesTransformFn(samples, maxSampleTime)); | ||
const numNegativeSamples = getNumNegativeSamples(samples); | ||
if (numNegativeSamples > 0) { | ||
Context.errorManager.record(this, ErrorType.InvalidValue, `Accumulated ${numNegativeSamples} negative samples`, numNegativeSamples); | ||
} | ||
const numTooLongSamples = getNumTooLongSamples(samples, maxSampleTime); | ||
if (numTooLongSamples > 0) { | ||
Context.errorManager.record(this, ErrorType.InvalidOverflow, `${numTooLongSamples} samples are longer than the maximum of ${maxSampleTime}`, numTooLongSamples); | ||
} | ||
} | ||
accumulateRawSamplesNanosSync(samples) { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
} | ||
const maxSampleTime = convertTimeUnitToNanos(MAX_SAMPLE_TIME, this.timeUnit); | ||
Context.metricsDatabase.transform(this, this.accumulateRawSamplesNanosTransformFn(samples, maxSampleTime)); | ||
const numTooLongSamples = getNumTooLongSamples(samples, maxSampleTime); | ||
if (numTooLongSamples > 0) { | ||
Context.errorManager.record(this, ErrorType.InvalidOverflow, `${numTooLongSamples} samples are longer than the maximum of ${maxSampleTime}`, numTooLongSamples); | ||
} | ||
} | ||
async testGetValue(ping = this.sendInPings[0]) { | ||
@@ -248,37 +335,37 @@ if (testOnlyCheck("testGetValue", LOG_TAG)) { | ||
constructor(meta, timeUnit) { | ||
_inner_1.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner_1, new InternalTimingDistributionMetricType(meta, timeUnit), "f"); | ||
_inner.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner, new InternalTimingDistributionMetricType(meta, timeUnit), "f"); | ||
} | ||
start() { | ||
const id = __classPrivateFieldGet(this, _inner_1, "f").start(); | ||
const id = __classPrivateFieldGet(this, _inner, "f").start(); | ||
return id; | ||
} | ||
setStart(id, startTime) { | ||
__classPrivateFieldGet(this, _inner_1, "f").setStart(id, startTime); | ||
__classPrivateFieldGet(this, _inner, "f").setStart(id, startTime); | ||
} | ||
stopAndAccumulate(id) { | ||
__classPrivateFieldGet(this, _inner_1, "f").stopAndAccumulate(id); | ||
__classPrivateFieldGet(this, _inner, "f").stopAndAccumulate(id); | ||
} | ||
setStopAndAccumulate(id, stopTime) { | ||
__classPrivateFieldGet(this, _inner_1, "f").setStopAndAccumulate(id, stopTime); | ||
__classPrivateFieldGet(this, _inner, "f").setStopAndAccumulate(id, stopTime); | ||
} | ||
accumulateRawSamplesNanos(samples) { | ||
__classPrivateFieldGet(this, _inner_1, "f").accumulateRawSamplesNanos(samples); | ||
__classPrivateFieldGet(this, _inner, "f").accumulateRawSamplesNanos(samples); | ||
} | ||
accumulateSamples(samples) { | ||
__classPrivateFieldGet(this, _inner_1, "f").accumulateSamples(samples); | ||
__classPrivateFieldGet(this, _inner, "f").accumulateSamples(samples); | ||
} | ||
setAccumulateSamples(samples) { | ||
__classPrivateFieldGet(this, _inner_1, "f").setAccumulateSamples(samples); | ||
__classPrivateFieldGet(this, _inner, "f").setAccumulateSamples(samples); | ||
} | ||
cancel(id) { | ||
__classPrivateFieldGet(this, _inner_1, "f").cancel(id); | ||
__classPrivateFieldGet(this, _inner, "f").cancel(id); | ||
} | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetValue(ping); | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetValue(ping); | ||
} | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetNumRecordedErrors(errorType, ping); | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetNumRecordedErrors(errorType, ping); | ||
} | ||
} | ||
_inner_1 = new WeakMap(); | ||
_inner = new WeakMap(); |
@@ -12,4 +12,4 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
}; | ||
var _inner_1; | ||
import { testOnlyCheck, truncateStringAtBoundaryWithError } from "../../utils.js"; | ||
var _inner; | ||
import { testOnlyCheck, truncateStringAtBoundaryWithError, truncateStringAtBoundaryWithErrorSync } from "../../utils.js"; | ||
import { MetricType } from "../index.js"; | ||
@@ -37,3 +37,3 @@ import { Context } from "../../context.js"; | ||
errorMessage: "URL metric does not support data URLs", | ||
errorType: ErrorType.InvalidValue, | ||
errorType: ErrorType.InvalidValue | ||
}; | ||
@@ -45,3 +45,3 @@ } | ||
errorMessage: `"${str}" does not start with a valid URL scheme`, | ||
errorType: ErrorType.InvalidValue, | ||
errorType: ErrorType.InvalidValue | ||
}; | ||
@@ -52,3 +52,3 @@ } | ||
payload() { | ||
return this._inner; | ||
return this.inner; | ||
} | ||
@@ -61,2 +61,18 @@ } | ||
set(url) { | ||
if (Context.isPlatformSync()) { | ||
this.setSync(url); | ||
} | ||
else { | ||
this.setAsync(url); | ||
} | ||
} | ||
setUrl(url) { | ||
if (Context.isPlatformSync()) { | ||
this.setSync(url.toString()); | ||
} | ||
else { | ||
this.setAsync(url.toString()); | ||
} | ||
} | ||
setAsync(url) { | ||
Context.dispatcher.launch(async () => { | ||
@@ -84,4 +100,22 @@ if (!this.shouldRecord(Context.uploadEnabled)) { | ||
} | ||
setUrl(url) { | ||
this.set(url.toString()); | ||
setSync(url) { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
} | ||
let formattedUrl; | ||
if (url.length > URL_MAX_LENGTH) { | ||
formattedUrl = truncateStringAtBoundaryWithErrorSync(this, url, URL_MAX_LENGTH); | ||
} | ||
else { | ||
formattedUrl = url; | ||
} | ||
try { | ||
const metric = new UrlMetric(formattedUrl); | ||
Context.metricsDatabase.record(this, metric); | ||
} | ||
catch (e) { | ||
if (e instanceof MetricValidationError) { | ||
e.recordErrorSync(this); | ||
} | ||
} | ||
} | ||
@@ -100,18 +134,18 @@ async testGetValue(ping = this.sendInPings[0]) { | ||
constructor(meta) { | ||
_inner_1.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner_1, new InternalUrlMetricType(meta), "f"); | ||
_inner.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner, new InternalUrlMetricType(meta), "f"); | ||
} | ||
set(url) { | ||
__classPrivateFieldGet(this, _inner_1, "f").set(url); | ||
__classPrivateFieldGet(this, _inner, "f").set(url); | ||
} | ||
setUrl(url) { | ||
__classPrivateFieldGet(this, _inner_1, "f").setUrl(url); | ||
__classPrivateFieldGet(this, _inner, "f").setUrl(url); | ||
} | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetValue(ping); | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetValue(ping); | ||
} | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetNumRecordedErrors(errorType, ping); | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetNumRecordedErrors(errorType, ping); | ||
} | ||
} | ||
_inner_1 = new WeakMap(); | ||
_inner = new WeakMap(); |
@@ -12,3 +12,3 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
}; | ||
var _inner_1; | ||
var _inner; | ||
import { MetricType } from "../index.js"; | ||
@@ -36,3 +36,3 @@ import { generateUUIDv4, testOnlyCheck } from "../../utils.js"; | ||
errorMessage: `"${str}" is not a valid UUID`, | ||
errorType: ErrorType.InvalidValue, | ||
errorType: ErrorType.InvalidValue | ||
}; | ||
@@ -43,3 +43,3 @@ } | ||
payload() { | ||
return this._inner; | ||
return this.inner; | ||
} | ||
@@ -51,2 +51,21 @@ } | ||
} | ||
set(value) { | ||
if (Context.isPlatformSync()) { | ||
this.setSync(value); | ||
} | ||
else { | ||
this.setAsync(value); | ||
} | ||
} | ||
generateAndSet() { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
} | ||
const value = generateUUIDv4(); | ||
this.set(value); | ||
return value; | ||
} | ||
setAsync(value) { | ||
Context.dispatcher.launch(() => this.setUndispatched(value)); | ||
} | ||
async setUndispatched(value) { | ||
@@ -70,12 +89,19 @@ if (!this.shouldRecord(Context.uploadEnabled)) { | ||
} | ||
set(value) { | ||
Context.dispatcher.launch(() => this.setUndispatched(value)); | ||
} | ||
generateAndSet() { | ||
setSync(value) { | ||
if (!this.shouldRecord(Context.uploadEnabled)) { | ||
return; | ||
} | ||
const value = generateUUIDv4(); | ||
this.set(value); | ||
return value; | ||
if (!value) { | ||
value = generateUUIDv4(); | ||
} | ||
let metric; | ||
try { | ||
metric = new UUIDMetric(value); | ||
Context.metricsDatabase.record(this, metric); | ||
} | ||
catch (e) { | ||
if (e instanceof MetricValidationError) { | ||
e.recordErrorSync(this); | ||
} | ||
} | ||
} | ||
@@ -94,18 +120,18 @@ async testGetValue(ping = this.sendInPings[0]) { | ||
constructor(meta) { | ||
_inner_1.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner_1, new InternalUUIDMetricType(meta), "f"); | ||
_inner.set(this, void 0); | ||
__classPrivateFieldSet(this, _inner, new InternalUUIDMetricType(meta), "f"); | ||
} | ||
set(value) { | ||
__classPrivateFieldGet(this, _inner_1, "f").set(value); | ||
__classPrivateFieldGet(this, _inner, "f").set(value); | ||
} | ||
generateAndSet() { | ||
return __classPrivateFieldGet(this, _inner_1, "f").generateAndSet(); | ||
return __classPrivateFieldGet(this, _inner, "f").generateAndSet(); | ||
} | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetValue(ping); | ||
async testGetValue(ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetValue(ping); | ||
} | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner_1, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner_1, "f").testGetNumRecordedErrors(errorType, ping); | ||
async testGetNumRecordedErrors(errorType, ping = __classPrivateFieldGet(this, _inner, "f").sendInPings[0]) { | ||
return __classPrivateFieldGet(this, _inner, "f").testGetNumRecordedErrors(errorType, ping); | ||
} | ||
} | ||
_inner_1 = new WeakMap(); | ||
_inner = new WeakMap(); |
@@ -15,3 +15,4 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
import { generateUUIDv4, testOnlyCheck } from "../utils.js"; | ||
import collectAndStorePing from "../pings/maker.js"; | ||
import collectAndStorePing from "../pings/maker/async.js"; | ||
import collectAndStorePingSync from "../pings/maker/sync.js"; | ||
import { Context } from "../context.js"; | ||
@@ -30,3 +31,32 @@ import log, { LoggingLevel } from "../log.js"; | ||
this.reasonCodes = (_a = meta.reasonCodes) !== null && _a !== void 0 ? _a : []; | ||
this.preciseTimestamps = meta.preciseTimestamps; | ||
} | ||
submit(reason) { | ||
if (Context.isPlatformSync()) { | ||
this.submitSync(reason); | ||
} | ||
else { | ||
this.submitAsync(reason); | ||
} | ||
} | ||
submitAsync(reason) { | ||
if (this.testCallback) { | ||
this.testCallback(reason) | ||
.then(() => { | ||
this.internalSubmit(reason, this.resolveTestPromiseFunction); | ||
}) | ||
.catch((e) => { | ||
log(LOG_TAG, [`There was an error validating "${this.name}" (${reason !== null && reason !== void 0 ? reason : "no reason"}):`, e], LoggingLevel.Error); | ||
this.internalSubmit(reason, this.rejectTestPromiseFunction); | ||
}); | ||
} | ||
else { | ||
this.internalSubmit(reason); | ||
} | ||
} | ||
internalSubmit(reason, testResolver) { | ||
Context.dispatcher.launch(async () => { | ||
await this.submitUndispatched(reason, testResolver); | ||
}); | ||
} | ||
async submitUndispatched(reason, testResolver) { | ||
@@ -55,22 +85,40 @@ if (!Context.initialized) { | ||
} | ||
internalSubmit(reason, testResolver) { | ||
Context.dispatcher.launch(async () => { | ||
await this.submitUndispatched(reason, testResolver); | ||
}); | ||
} | ||
submit(reason) { | ||
submitSync(reason) { | ||
if (this.testCallback) { | ||
this.testCallback(reason) | ||
.then(() => { | ||
this.internalSubmit(reason, this.resolveTestPromiseFunction); | ||
this.internalSubmitSync(reason, this.resolveTestPromiseFunction); | ||
}) | ||
.catch(e => { | ||
.catch((e) => { | ||
log(LOG_TAG, [`There was an error validating "${this.name}" (${reason !== null && reason !== void 0 ? reason : "no reason"}):`, e], LoggingLevel.Error); | ||
this.internalSubmit(reason, this.rejectTestPromiseFunction); | ||
this.internalSubmitSync(reason, this.rejectTestPromiseFunction); | ||
}); | ||
} | ||
else { | ||
this.internalSubmit(reason); | ||
this.internalSubmitSync(reason); | ||
} | ||
} | ||
internalSubmitSync(reason, testResolver) { | ||
if (!Context.initialized) { | ||
log(LOG_TAG, "Glean must be initialized before submitting pings.", LoggingLevel.Info); | ||
return; | ||
} | ||
if (!Context.uploadEnabled && !isDeletionRequest(this.name)) { | ||
log(LOG_TAG, "Glean disabled: not submitting pings. Glean may still submit the deletion-request ping.", LoggingLevel.Info); | ||
return; | ||
} | ||
let correctedReason = reason; | ||
if (reason && !this.reasonCodes.includes(reason)) { | ||
log(LOG_TAG, `Invalid reason code ${reason} from ${this.name}. Ignoring.`, LoggingLevel.Warn); | ||
correctedReason = undefined; | ||
} | ||
const identifier = generateUUIDv4(); | ||
collectAndStorePingSync(identifier, this, correctedReason); | ||
if (testResolver) { | ||
testResolver(); | ||
this.resolveTestPromiseFunction = undefined; | ||
this.rejectTestPromiseFunction = undefined; | ||
this.testCallback = undefined; | ||
} | ||
} | ||
async testBeforeNextSubmit(callbackFn) { | ||
@@ -77,0 +125,0 @@ if (testOnlyCheck("testBeforeNextSubmit", LOG_TAG)) { |
import { Context } from "../context.js"; | ||
import EventsDatabase from "../metrics/events_database/index.js"; | ||
import EventsDatabase from "../metrics/events_database/async.js"; | ||
export async function testRestartGlean(timeOffset = 1000 * 60) { | ||
@@ -4,0 +4,0 @@ Context.startTime.setTime(Context.startTime.getTime() + timeOffset); |
import TestPlatform from "../../platform/test/index.js"; | ||
import { Context } from "../context.js"; | ||
import { testResetEvents } from "../events/utils.js"; | ||
import Glean from "../glean.js"; | ||
import { testResetEvents } from "../events/utils/async.js"; | ||
import Glean from "../glean/async.js"; | ||
export async function testInitializeGlean(applicationId, uploadEnabled = true, config) { | ||
@@ -6,0 +6,0 @@ Context.testing = true; |
@@ -45,2 +45,11 @@ import { v4 as UUIDv4 } from "uuid"; | ||
} | ||
export function extractBooleanFromString(v) { | ||
if (v.toLowerCase() === "true") { | ||
return true; | ||
} | ||
else if (v.toLowerCase() === "false") { | ||
return false; | ||
} | ||
return undefined; | ||
} | ||
export function sanitizeApplicationId(applicationId) { | ||
@@ -83,2 +92,12 @@ return applicationId.replace(/[^a-z0-9]+/gi, "-").toLowerCase(); | ||
} | ||
export function truncateStringAtBoundaryWithErrorSync(metric, value, length) { | ||
if (!isString(value)) { | ||
throw new MetricValidationError(`Expected string, got ${JSON.stringify(value)}`); | ||
} | ||
const truncated = value.substring(0, length); | ||
if (truncated !== value) { | ||
Context.errorManager.record(metric, ErrorType.InvalidOverflow, `Value length ${value.length} exceeds maximum of ${length}.`); | ||
} | ||
return truncated; | ||
} | ||
export function testOnlyCheck(name, logTag = LOG_TAG) { | ||
@@ -113,1 +132,4 @@ if (!Context.testing) { | ||
} | ||
export function isWindowObjectUnavailable() { | ||
return typeof window === "undefined"; | ||
} |
import platform from "../platform/browser/web/index.js"; | ||
import base from "./base.js"; | ||
import { baseSync } from "./base/sync.js"; | ||
export { default as Uploader, UploadResult, UploadResultStatus } from "../core/upload/uploader.js"; | ||
export default base(platform); | ||
export default baseSync(platform); |
import uploader from "../uploader.js"; | ||
import info from "./platform_info.js"; | ||
import Storage from "./storage.js"; | ||
const WebPlaftorm = { | ||
const WebPlatform = { | ||
Storage, | ||
@@ -11,2 +11,2 @@ uploader, | ||
}; | ||
export default WebPlaftorm; | ||
export default WebPlatform; |
const BrowserPlatformInfo = { | ||
os() { | ||
const ua = navigator.userAgent; | ||
let ua; | ||
if (!!navigator && !!navigator.userAgent) { | ||
ua = navigator.userAgent; | ||
} | ||
else { | ||
ua = "Unknown"; | ||
} | ||
if (ua.includes("Windows")) { | ||
return Promise.resolve("Windows"); | ||
return "Windows"; | ||
} | ||
if (/tvOS/i.test(ua)) { | ||
return Promise.resolve("TvOS"); | ||
return "TvOS"; | ||
} | ||
if (/Watch( OS)?/i.test(ua)) { | ||
return Promise.resolve("WatchOS"); | ||
return "WatchOS"; | ||
} | ||
if (/iPhone|iPad|iOS/i.test(ua)) { | ||
return Promise.resolve("iOS"); | ||
return "iOS"; | ||
} | ||
if (/Mac OS X|macOS/i.test(ua)) { | ||
return Promise.resolve("Darwin"); | ||
return "Darwin"; | ||
} | ||
if (/Android/i.test(ua)) { | ||
return Promise.resolve("Android"); | ||
return "Android"; | ||
} | ||
if (/CrOS/i.test(ua)) { | ||
return Promise.resolve("ChromeOS"); | ||
return "ChromeOS"; | ||
} | ||
if (/WebOS/i.test(ua)) { | ||
return Promise.resolve("WebOS"); | ||
return "WebOS"; | ||
} | ||
if (/Linux/i.test(ua)) { | ||
return Promise.resolve("Linux"); | ||
return "Linux"; | ||
} | ||
if (/OpenBSD/i.test(ua)) { | ||
return Promise.resolve("OpenBSD"); | ||
return "OpenBSD"; | ||
} | ||
if (/FreeBSD/i.test(ua)) { | ||
return Promise.resolve("FreeBSD"); | ||
return "FreeBSD"; | ||
} | ||
if (/NetBSD/i.test(ua)) { | ||
return Promise.resolve("NetBSD"); | ||
return "NetBSD"; | ||
} | ||
if (/SunOS/i.test(ua)) { | ||
return Promise.resolve("SunOS"); | ||
return "SunOS"; | ||
} | ||
if (/AIX/i.test(ua)) { | ||
return Promise.resolve("IBM_AIX"); | ||
return "IBM_AIX"; | ||
} | ||
return Promise.resolve("Unknown"); | ||
return "Unknown"; | ||
}, | ||
async osVersion() { | ||
return Promise.resolve("Unknown"); | ||
osVersion() { | ||
return "Unknown"; | ||
}, | ||
async arch() { | ||
return Promise.resolve("Unknown"); | ||
arch() { | ||
return "Unknown"; | ||
}, | ||
async locale() { | ||
return Promise.resolve(navigator.language || "und"); | ||
locale() { | ||
return navigator.language || "und"; | ||
} | ||
}; | ||
export default BrowserPlatformInfo; |
import log, { LoggingLevel } from "../../../core/log.js"; | ||
import { deleteKeyFromNestedObject, getValueFromNestedObject, updateNestedObject } from "../../../core/storage/utils.js"; | ||
import { isJSONValue, isObject, isUndefined } from "../../../core/utils.js"; | ||
import { isWindowObjectUnavailable } from "../../../core/utils.js"; | ||
const LOG_TAG = "platform.web.Storage"; | ||
const DATABASE_NAME = "Glean"; | ||
const STORE_NAME = "Main"; | ||
var DatabaseTransactionModes; | ||
(function (DatabaseTransactionModes) { | ||
DatabaseTransactionModes["ReadOnly"] = "readonly"; | ||
DatabaseTransactionModes["ReadWrite"] = "readwrite"; | ||
})(DatabaseTransactionModes || (DatabaseTransactionModes = {})); | ||
var IDBWrapper; | ||
(function (IDBWrapper) { | ||
let db; | ||
function withDatabase(fn) { | ||
if (db) { | ||
return fn(); | ||
} | ||
return new Promise((resolve, reject) => { | ||
const openRequest = self.indexedDB.open(DATABASE_NAME); | ||
openRequest.onerror = () => { | ||
log(LOG_TAG, ["Unable to open Glean database.", openRequest.error]); | ||
reject(openRequest.error); | ||
}; | ||
openRequest.onsuccess = () => { | ||
db = openRequest.result; | ||
fn() | ||
.then(() => resolve()) | ||
.catch(e => reject(e)); | ||
}; | ||
openRequest.onupgradeneeded = () => { | ||
openRequest.result.createObjectStore(STORE_NAME); | ||
}; | ||
}); | ||
} | ||
async function withStoredValue(key, fn, mode) { | ||
await withDatabase(async () => { | ||
const transaction = db === null || db === void 0 ? void 0 : db.transaction(STORE_NAME, mode); | ||
if (!transaction) { | ||
throw new Error("IMPOSSIBLE: Unable to perform database transaction. Database is not initialized."); | ||
} | ||
const completed = new Promise((resolve, reject) => { | ||
transaction.oncomplete = () => resolve(); | ||
transaction.onerror = transaction.onabort = e => reject(e); | ||
}); | ||
const store = transaction.objectStore(STORE_NAME); | ||
const storedValue = await new Promise((resolve, reject) => { | ||
const req = store.get(key); | ||
req.onsuccess = () => resolve(req.result); | ||
req.onerror = () => reject(req.error); | ||
}); | ||
let correctedValue; | ||
if (isUndefined(storedValue)) { | ||
correctedValue = {}; | ||
} | ||
else if (isJSONValue(storedValue) && isObject(storedValue)) { | ||
correctedValue = storedValue; | ||
} | ||
else { | ||
log(LOG_TAG, ["Unexpected data found in storage. Overwriting.", storedValue], LoggingLevel.Warn); | ||
correctedValue = {}; | ||
} | ||
await fn(correctedValue, store); | ||
await completed; | ||
}); | ||
} | ||
IDBWrapper.withStoredValue = withStoredValue; | ||
})(IDBWrapper || (IDBWrapper = {})); | ||
class WebStore { | ||
@@ -74,47 +10,61 @@ constructor(rootKey) { | ||
} | ||
async get(index = []) { | ||
get(index = []) { | ||
if (isWindowObjectUnavailable()) { | ||
return; | ||
} | ||
let result; | ||
await IDBWrapper.withStoredValue(this.rootKey, (value) => { | ||
try { | ||
const json = localStorage.getItem(this.rootKey) || "{}"; | ||
const obj = JSON.parse(json); | ||
if (index.length > 0) { | ||
result = getValueFromNestedObject(value, index); | ||
result = getValueFromNestedObject(obj, index); | ||
} | ||
else { | ||
result = Object.keys(value).length === 0 ? undefined : value; | ||
result = Object.keys(obj).length === 0 ? undefined : obj; | ||
} | ||
return Promise.resolve(); | ||
}, DatabaseTransactionModes.ReadOnly); | ||
} | ||
catch (err) { | ||
log(LOG_TAG, ["Unable to fetch value from local storage.", err], LoggingLevel.Error); | ||
} | ||
return result; | ||
} | ||
async update(index, transformFn) { | ||
await IDBWrapper.withStoredValue(this.rootKey, async (value, store) => { | ||
await new Promise((resolve, reject) => { | ||
const updatedObj = updateNestedObject(value, index, transformFn); | ||
const request = store.put(updatedObj, this.rootKey); | ||
request.onsuccess = resolve; | ||
request.onerror = () => reject(request.error); | ||
}); | ||
}, DatabaseTransactionModes.ReadWrite); | ||
update(index, transformFn) { | ||
if (isWindowObjectUnavailable()) { | ||
return; | ||
} | ||
try { | ||
const json = localStorage.getItem(this.rootKey) || "{}"; | ||
const obj = JSON.parse(json); | ||
const updatedObj = updateNestedObject(obj, index, transformFn); | ||
localStorage.setItem(this.rootKey, JSON.stringify(updatedObj)); | ||
} | ||
catch (err) { | ||
log(LOG_TAG, ["Unable to update value from local storage.", err], LoggingLevel.Error); | ||
} | ||
} | ||
async delete(index) { | ||
await IDBWrapper.withStoredValue(this.rootKey, async (value, store) => { | ||
delete(index) { | ||
if (isWindowObjectUnavailable()) { | ||
return; | ||
} | ||
try { | ||
const json = localStorage.getItem(this.rootKey) || "{}"; | ||
const obj = JSON.parse(json); | ||
if (index.length === 0) { | ||
store.delete(this.rootKey); | ||
localStorage.removeItem(this.rootKey); | ||
} | ||
else { | ||
await new Promise((resolve, reject) => { | ||
try { | ||
const updatedObj = deleteKeyFromNestedObject(value, index); | ||
const request = store.put(updatedObj, this.rootKey); | ||
request.onsuccess = () => resolve(); | ||
request.onerror = () => reject(request.error); | ||
} | ||
catch (e) { | ||
log(this.logTag, [`Error attempting to delete key ${index.toString()} from storage. Ignoring.`, e], LoggingLevel.Warn); | ||
resolve(); | ||
} | ||
}); | ||
try { | ||
const updatedObj = deleteKeyFromNestedObject(obj, index); | ||
localStorage.setItem(this.rootKey, JSON.stringify(updatedObj)); | ||
} | ||
catch (e) { | ||
log(this.logTag, [`Error attempting to delete key ${index.toString()} from storage. Ignoring.`, e], LoggingLevel.Warn); | ||
} | ||
} | ||
}, DatabaseTransactionModes.ReadWrite); | ||
} | ||
catch (err) { | ||
log(LOG_TAG, ["Unable to delete value from storage.", err], LoggingLevel.Error); | ||
} | ||
} | ||
} | ||
export default WebStore; |
import log, { LoggingLevel } from "../../core/log.js"; | ||
import { updateNestedObject, getValueFromNestedObject, deleteKeyFromNestedObject } from "../../core/storage/utils.js"; | ||
const LOG_TAG = "plaftom.test.Storage"; | ||
const LOG_TAG = "platform.test.Storage"; | ||
let globalStore = {}; | ||
@@ -5,0 +5,0 @@ class MockStore { |
import { CompactEncrypt, importJWK, calculateJwkThumbprint } from "jose"; | ||
import Plugin from "./index.js"; | ||
import CoreEvents from "../core/events/index.js"; | ||
import CoreEvents from "../core/events/async.js"; | ||
const JWE_ALGORITHM = "ECDH-ES"; | ||
@@ -19,3 +19,3 @@ const JWE_CONTENT_ENCODING = "A256GCM"; | ||
enc: JWE_CONTENT_ENCODING, | ||
typ: "JWE", | ||
typ: "JWE" | ||
}) | ||
@@ -22,0 +22,0 @@ .encrypt(key); |
@@ -22,5 +22,4 @@ import type Plugin from "../plugins/index.js"; | ||
httpClient?: Uploader; | ||
readonly architecture?: string; | ||
readonly osVersion?: string; | ||
readonly buildDate?: Date; | ||
readonly migrateFromLegacyStorage?: boolean; | ||
} | ||
@@ -32,6 +31,5 @@ export declare class Configuration implements ConfigurationInterface { | ||
readonly serverEndpoint: string; | ||
readonly architecture?: string; | ||
readonly osVersion?: string; | ||
readonly buildDate?: Date; | ||
readonly maxEvents: number; | ||
readonly migrateFromLegacyStorage?: boolean; | ||
debug: DebugOptions; | ||
@@ -38,0 +36,0 @@ httpClient?: Uploader; |
export declare const GLEAN_SCHEMA_VERSION = 1; | ||
export declare const GLEAN_VERSION = "1.3.0"; | ||
export declare const GLEAN_VERSION = "3.0.0"; | ||
export declare const PING_INFO_STORAGE = "glean_ping_info"; | ||
@@ -4,0 +4,0 @@ export declare const CLIENT_INFO_STORAGE = "glean_client_info"; |
@@ -1,12 +0,18 @@ | ||
import type MetricsDatabase from "./metrics/database.js"; | ||
import type EventsDatabase from "./metrics/events_database/index.js"; | ||
import type PingsDatabase from "./pings/database.js"; | ||
import type ErrorManager from "./error/index.js"; | ||
import type Platform from "../platform/index.js"; | ||
import type MetricsDatabase from "./metrics/database/async.js"; | ||
import type MetricsDatabaseSync from "./metrics/database/sync.js"; | ||
import type EventsDatabase from "./metrics/events_database/async.js"; | ||
import type { EventsDatabaseSync } from "./metrics/events_database/sync.js"; | ||
import type PingsDatabase from "./pings/database/async.js"; | ||
import type PingsDatabaseSync from "./pings/database/sync.js"; | ||
import type ErrorManager from "./error/async.js"; | ||
import type ErrorManagerSync from "./error/sync.js"; | ||
import type Platform from "../platform/async.js"; | ||
import type PlatformSync from "../platform/sync.js"; | ||
import type { CoreMetrics } from "./internal_metrics/async.js"; | ||
import type { CoreMetricsSync } from "./internal_metrics/sync.js"; | ||
import type { Configuration } from "./config.js"; | ||
import type CorePings from "./internal_pings.js"; | ||
import type { Metric } from "./metrics/metric.js"; | ||
import type { JSONValue } from "./utils.js"; | ||
import Dispatcher from "./dispatcher.js"; | ||
import type { Configuration } from "./config.js"; | ||
import type CorePings from "./internal_pings.js"; | ||
import type { CoreMetrics } from "./internal_metrics.js"; | ||
/** | ||
@@ -26,17 +32,17 @@ * This class holds all of the Glean singleton's state and internal dependencies. | ||
private static _instance?; | ||
private _dispatcher; | ||
private _platform; | ||
private _corePings; | ||
private _coreMetrics; | ||
private _uploadEnabled; | ||
private _metricsDatabase; | ||
private _eventsDatabase; | ||
private _pingsDatabase; | ||
private _errorManager; | ||
private _applicationId; | ||
private _config; | ||
private _initialized; | ||
private _testing; | ||
private _supportedMetrics; | ||
private _startTime; | ||
private dispatcher; | ||
private platform; | ||
private corePings; | ||
private coreMetrics; | ||
private uploadEnabled; | ||
private metricsDatabase; | ||
private eventsDatabase; | ||
private pingsDatabase; | ||
private errorManager; | ||
private applicationId; | ||
private config; | ||
private initialized; | ||
private testing; | ||
private supportedMetrics; | ||
private startTime; | ||
private constructor(); | ||
@@ -53,10 +59,10 @@ static get instance(): Context; | ||
static set uploadEnabled(upload: boolean); | ||
static get metricsDatabase(): MetricsDatabase; | ||
static set metricsDatabase(db: MetricsDatabase); | ||
static get eventsDatabase(): EventsDatabase; | ||
static set eventsDatabase(db: EventsDatabase); | ||
static get pingsDatabase(): PingsDatabase; | ||
static set pingsDatabase(db: PingsDatabase); | ||
static get errorManager(): ErrorManager; | ||
static set errorManager(db: ErrorManager); | ||
static get metricsDatabase(): MetricsDatabase | MetricsDatabaseSync; | ||
static set metricsDatabase(db: MetricsDatabase | MetricsDatabaseSync); | ||
static get eventsDatabase(): EventsDatabase | EventsDatabaseSync; | ||
static set eventsDatabase(db: EventsDatabase | EventsDatabaseSync); | ||
static get pingsDatabase(): PingsDatabase | PingsDatabaseSync; | ||
static set pingsDatabase(db: PingsDatabase | PingsDatabaseSync); | ||
static get errorManager(): ErrorManager | ErrorManagerSync; | ||
static set errorManager(db: ErrorManager | ErrorManagerSync); | ||
static get applicationId(): string; | ||
@@ -73,7 +79,8 @@ static set applicationId(id: string); | ||
static set corePings(pings: CorePings); | ||
static get coreMetrics(): CoreMetrics; | ||
static set coreMetrics(metrics: CoreMetrics); | ||
static set platform(platform: Platform); | ||
static get platform(): Platform; | ||
static get coreMetrics(): CoreMetrics | CoreMetricsSync; | ||
static set coreMetrics(metrics: CoreMetrics | CoreMetricsSync); | ||
static set platform(platform: Platform | PlatformSync); | ||
static get platform(): Platform | PlatformSync; | ||
static isPlatformSet(): boolean; | ||
static isPlatformSync(): boolean; | ||
static getSupportedMetric(type: string): (new (v: unknown) => Metric<JSONValue, JSONValue>) | undefined; | ||
@@ -80,0 +87,0 @@ /** |
@@ -8,3 +8,3 @@ export declare const enum DispatcherState { | ||
} | ||
declare type Task = () => Promise<void>; | ||
type Task = () => Promise<void>; | ||
/** | ||
@@ -11,0 +11,0 @@ * A task dispatcher for async tasks. |
@@ -26,1 +26,16 @@ import type { Histogram } from "../../histogram/histogram"; | ||
export declare function extractAccumulatedValuesFromJsonValue(jsonValue?: JSONValue): number[]; | ||
/** | ||
* Get a count of all samples with a value less than 0. | ||
* | ||
* @param samples Samples for a distribution. | ||
* @returns Count of samples that had a value less than 0. | ||
*/ | ||
export declare function getNumNegativeSamples(samples: number[]): number; | ||
/** | ||
* Get a count of all samples that exceed the max value. | ||
* | ||
* @param samples Samples for a distribution. | ||
* @param max The max allowed value. | ||
* @returns Count of samples that exceed the max value. | ||
*/ | ||
export declare function getNumTooLongSamples(samples: number[], max: number): number; |
import type { JSONObject } from "../../utils.js"; | ||
import type { MetricValidationResult } from "../metric.js"; | ||
import { Metric } from "../metric.js"; | ||
export declare type ExtraValues = string | boolean | number; | ||
export declare type ExtraMap = Record<string, ExtraValues>; | ||
export type ExtraValues = string | boolean | number; | ||
export type ExtraMap = Record<string, ExtraValues>; | ||
export interface Event extends JSONObject { | ||
@@ -7,0 +7,0 @@ readonly category: string; |
@@ -35,3 +35,3 @@ import type { JSONValue } from "../utils.js"; | ||
* | ||
* @returns The generated identifier. If `category` is empty, it's ommitted. Otherwise, | ||
* @returns The generated identifier. If `category` is empty, it's omitted. Otherwise, | ||
* it's the combination of the metric's `category` and `name`. | ||
@@ -43,3 +43,3 @@ */ | ||
* | ||
* @returns The generated identifier. If `category` is empty, it's ommitted. Otherwise, | ||
* @returns The generated identifier. If `category` is empty, it's omitted. Otherwise, | ||
* it's the combination of the metric's `category`, `name` and `label`. | ||
@@ -49,2 +49,9 @@ */ | ||
/** | ||
* The metric's unique identifier, including the category, name and label. | ||
* | ||
* @returns The generated identifier. If `category` is empty, it's omitted. Otherwise, | ||
* it's the combination of the metric's `category`, `name` and `label`. | ||
*/ | ||
identifierSync(): string; | ||
/** | ||
* Verify whether or not this metric instance should be recorded. | ||
@@ -51,0 +58,0 @@ * |
@@ -8,3 +8,3 @@ import type { JSONValue } from "../utils.js"; | ||
} | ||
export declare type MetricValidationResult = { | ||
export type MetricValidationResult = { | ||
type: MetricValidation.Success; | ||
@@ -20,2 +20,3 @@ } | { | ||
recordError(metric: MetricType): Promise<void>; | ||
recordErrorSync(metric: MetricType): void; | ||
} | ||
@@ -35,3 +36,3 @@ /** | ||
export declare abstract class Metric<InternalRepresentation extends JSONValue, PayloadRepresentation extends JSONValue> { | ||
protected _inner: InternalRepresentation; | ||
protected inner: InternalRepresentation; | ||
constructor(v: unknown); | ||
@@ -66,3 +67,3 @@ /** | ||
* @param v The value to verify. | ||
* @returns Whether or not validation was successfull. | ||
* @returns Whether or not validation was successful. | ||
*/ | ||
@@ -69,0 +70,0 @@ abstract validate(v: unknown): MetricValidationResult; |
@@ -20,4 +20,7 @@ import type { CommonMetricData } from "../index.js"; | ||
constructor(meta: CommonMetricData); | ||
add(amount?: number): void; | ||
private transformFn; | ||
addAsync(amount?: number): void; | ||
/** | ||
* An implemention of `add` that does not dispatch the recording task. | ||
* An implementation of `add` that does not dispatch the recording task. | ||
* | ||
@@ -31,3 +34,8 @@ * # Important | ||
addUndispatched(amount?: number): Promise<void>; | ||
add(amount?: number): void; | ||
/** | ||
* A synchronous implementation of add. | ||
* | ||
* @param amount The amount we want to add. | ||
*/ | ||
addSync(amount?: number): void; | ||
testGetValue(ping?: string): Promise<number | undefined>; | ||
@@ -34,0 +42,0 @@ } |
@@ -5,3 +5,3 @@ import type { CommonMetricData } from "../index.js"; | ||
import { Metric } from "../metric.js"; | ||
declare type CustomDistributionInternalRepresentation = { | ||
type CustomDistributionInternalRepresentation = { | ||
values: number[]; | ||
@@ -13,3 +13,3 @@ rangeMin: number; | ||
}; | ||
export declare type CustomDistributionPayloadRepresentation = { | ||
export type CustomDistributionPayloadRepresentation = { | ||
values: Record<number, number>; | ||
@@ -16,0 +16,0 @@ sum: number; |
import type { CommonMetricData } from "../index.js"; | ||
import type { MetricValidationResult } from "../metric.js"; | ||
import { MetricType } from "../index.js"; | ||
import TimeUnit from "../../metrics/time_unit.js"; | ||
import type { MetricValidationResult } from "../metric.js"; | ||
import { Metric } from "../metric.js"; | ||
/** | ||
* Builds the formatted timezone offset string frim a given timezone. | ||
* Builds the formatted timezone offset string from a given timezone. | ||
* | ||
@@ -16,3 +16,3 @@ * The format of the resulting string is `+02:00`. | ||
export declare function formatTimezoneOffset(timezone: number): string; | ||
export declare type DatetimeInternalRepresentation = { | ||
export type DatetimeInternalRepresentation = { | ||
timeUnit: TimeUnit; | ||
@@ -25,2 +25,3 @@ timezone: number; | ||
static fromDate(v: unknown, timeUnit: TimeUnit): DatetimeMetric; | ||
static fromRawDatetime(isoString: string, timezoneOffset: number, timeUnit: TimeUnit): DatetimeMetric; | ||
/** | ||
@@ -66,4 +67,7 @@ * Gets the datetime data as a Date object. | ||
constructor(meta: CommonMetricData, timeUnit: string); | ||
set(value?: Date): void; | ||
private truncateDate; | ||
setAsync(value?: Date): void; | ||
/** | ||
* An implemention of `set` that does not dispatch the recording task. | ||
* An implementation of `set` that does not dispatch the recording task. | ||
* | ||
@@ -77,4 +81,16 @@ * # Important | ||
setUndispatched(value?: Date): Promise<void>; | ||
set(value?: Date): void; | ||
setSync(value?: Date): void; | ||
/** | ||
* Set a datetime metric from raw values. | ||
* | ||
* # Important | ||
* This method should **never** be exposed to users. This is used solely | ||
* for migrating IDB data to LocalStorage. | ||
* | ||
* @param isoString Raw isoString. | ||
* @param timezone Raw timezone. | ||
* @param timeUnit Raw timeUnit. | ||
*/ | ||
setSyncRaw(isoString: string, timezone: number, timeUnit: TimeUnit): void; | ||
/** | ||
* Test-only API | ||
@@ -81,0 +97,0 @@ * |
@@ -15,4 +15,13 @@ import type { CommonMetricData } from "../index.js"; | ||
/** | ||
* An implemention of `record` that does not dispatch the recording task. | ||
* Record an event. | ||
* | ||
* @param extra optional. Used for events where additional richer context is needed. | ||
* The maximum length for string values is 100 bytes. | ||
* @param timestamp The event timestamp, defaults to now. | ||
*/ | ||
record(extra?: SpecificExtraMap, timestamp?: number): void; | ||
recordAsync(timestamp: number, extra?: SpecificExtraMap): void; | ||
/** | ||
* An implementation of `record` that does not dispatch the recording task. | ||
* | ||
* # Important | ||
@@ -28,10 +37,4 @@ * | ||
recordUndispatched(extra?: ExtraMap, timestamp?: number): Promise<void>; | ||
recordSync(timestamp: number, extra?: SpecificExtraMap): void; | ||
/** | ||
* Record an event. | ||
* | ||
* @param extra optional. Used for events where additional richer context is needed. | ||
* The maximum length for string values is 100 bytes. | ||
*/ | ||
record(extra?: SpecificExtraMap): void; | ||
/** | ||
* Test-only API | ||
@@ -38,0 +41,0 @@ * |
@@ -47,3 +47,12 @@ import type { CommonMetricData, MetricType } from "../index.js"; | ||
export declare function getValidDynamicLabel(metric: MetricType): Promise<string>; | ||
declare type SupportedLabeledTypes = CounterMetricType | BooleanMetricType | StringMetricType; | ||
/** | ||
* Checks if the dynamic label stored in the metric data is | ||
* valid. If not, record an error and store data in the "__other__" | ||
* label. | ||
* | ||
* @param metric the metric to record to. | ||
* @returns a valid label that can be used to store data. | ||
*/ | ||
export declare function getValidDynamicLabelSync(metric: MetricType): string; | ||
type SupportedLabeledTypes = CounterMetricType | BooleanMetricType | StringMetricType; | ||
declare class LabeledMetricType<T extends SupportedLabeledTypes> { | ||
@@ -50,0 +59,0 @@ [label: string]: T; |
@@ -5,4 +5,4 @@ import type { DistributionData } from "../distributions.js"; | ||
import { Metric } from "../metric.js"; | ||
declare type MemoryDistributionInternalRepresentation = number[]; | ||
export declare type MemoryDistributionPayloadRepresentation = { | ||
type MemoryDistributionInternalRepresentation = number[]; | ||
export type MemoryDistributionPayloadRepresentation = { | ||
values: Record<number, number>; | ||
@@ -9,0 +9,0 @@ sum: number; |
import type { CommonMetricData } from "../index.js"; | ||
import type { MetricValidationResult } from "../metric.js"; | ||
import { Metric } from "../metric.js"; | ||
export declare type Rate = { | ||
export type Rate = { | ||
numerator: number; | ||
@@ -6,0 +6,0 @@ denominator: number; |
import type { CommonMetricData } from "../index.js"; | ||
import type { MetricValidationResult } from "../metric.js"; | ||
import { MetricType } from "../index.js"; | ||
import type { MetricValidationResult } from "../metric.js"; | ||
import { Metric } from "../metric.js"; | ||
@@ -20,4 +20,6 @@ export declare const MAX_LENGTH_VALUE = 100; | ||
constructor(meta: CommonMetricData); | ||
set(value: string): void; | ||
setAsync(value: string): void; | ||
/** | ||
* An implemention of `set` that does not dispatch the recording task. | ||
* An implementation of `set` that does not dispatch the recording task. | ||
* | ||
@@ -31,3 +33,3 @@ * # Important | ||
setUndispatched(value: string): Promise<void>; | ||
set(value: string): void; | ||
setSync(value: string): void; | ||
testGetValue(ping?: string): Promise<string | undefined>; | ||
@@ -34,0 +36,0 @@ } |
import type { CommonMetricData } from "../index.js"; | ||
import type { MetricValidationResult } from "../metric.js"; | ||
import TimeUnit from "../time_unit.js"; | ||
import { MetricType } from "../index.js"; | ||
import type { MetricValidationResult } from "../metric.js"; | ||
import { Metric } from "../metric.js"; | ||
export declare type TimespanInternalRepresentation = { | ||
export type TimespanInternalRepresentation = { | ||
timeUnit: TimeUnit; | ||
timespan: number; | ||
}; | ||
export declare type TimespanPayloadRepresentation = { | ||
export type TimespanPayloadRepresentation = { | ||
time_unit: TimeUnit; | ||
@@ -32,4 +32,12 @@ value: number; | ||
constructor(meta: CommonMetricData, timeUnit: string); | ||
start(): void; | ||
stop(): void; | ||
cancel(): void; | ||
setRawNanos(elapsed: number): void; | ||
startAsync(): void; | ||
stopAsync(): void; | ||
cancelAsync(): void; | ||
setRawNanosAsync(elapsed: number): void; | ||
/** | ||
* An implemention of `setRaw` that does not dispatch the recording task. | ||
* An implementation of `setRaw` that does not dispatch the recording task. | ||
* | ||
@@ -43,6 +51,8 @@ * # Important | ||
setRawUndispatched(elapsed: number): Promise<void>; | ||
start(): void; | ||
stop(): void; | ||
cancel(): void; | ||
setRawNanos(elapsed: number): void; | ||
setRawAsync(elapsed: number): Promise<void>; | ||
startSync(): void; | ||
stopSync(): void; | ||
cancelSync(): void; | ||
setRawNanosSync(elapsed: number): void; | ||
setRawSync(elapsed: number): void; | ||
testGetValue(ping?: string): Promise<number | undefined>; | ||
@@ -49,0 +59,0 @@ } |
@@ -5,4 +5,4 @@ import type { CommonMetricData } from "../index.js"; | ||
import { Metric } from "../metric.js"; | ||
declare type TimingDistributionInternalRepresentation = number[]; | ||
export declare type TimingDistributionPayloadRepresentation = { | ||
type TimingDistributionInternalRepresentation = number[]; | ||
export type TimingDistributionPayloadRepresentation = { | ||
values: Record<number, number>; | ||
@@ -9,0 +9,0 @@ sum: number; |
import type { CommonMetricData } from "../index.js"; | ||
import type { MetricValidationResult } from "../metric.js"; | ||
import { MetricType } from "../index.js"; | ||
import type { MetricValidationResult } from "../metric.js"; | ||
import { Metric } from "../metric.js"; | ||
@@ -19,4 +19,7 @@ export declare class UUIDMetric extends Metric<string, string> { | ||
constructor(meta: CommonMetricData); | ||
set(value: string): void; | ||
generateAndSet(): string | undefined; | ||
setAsync(value: string): void; | ||
/** | ||
* An implemention of `set` that does not dispatch the recording task. | ||
* An implementation of `set` that does not dispatch the recording task. | ||
* | ||
@@ -30,4 +33,3 @@ * # Important | ||
setUndispatched(value: string): Promise<void>; | ||
set(value: string): void; | ||
generateAndSet(): string | undefined; | ||
setSync(value: string): void; | ||
testGetValue(ping?: string): Promise<string | undefined>; | ||
@@ -34,0 +36,0 @@ } |
@@ -9,2 +9,3 @@ /** | ||
readonly reasonCodes?: string[]; | ||
readonly preciseTimestamps?: boolean; | ||
} |
import type CommonPingData from "./common_ping_data.js"; | ||
declare type ValidatorFunction = (reason?: string) => Promise<void>; | ||
declare type PromiseCallback = (value: void | PromiseLike<void>) => void; | ||
type ValidatorFunction = (reason?: string) => Promise<void>; | ||
type PromiseCallback = (value: void | PromiseLike<void>) => void; | ||
export declare class InternalPingType implements CommonPingData { | ||
@@ -9,2 +9,3 @@ readonly name: string; | ||
readonly reasonCodes: string[]; | ||
readonly preciseTimestamps?: boolean; | ||
private resolveTestPromiseFunction?; | ||
@@ -14,4 +15,7 @@ private rejectTestPromiseFunction?; | ||
constructor(meta: CommonPingData); | ||
submit(reason?: string): void; | ||
submitAsync(reason?: string): void; | ||
private internalSubmit; | ||
/** | ||
* An implemention of `submit` that does not dispatch the submission task. | ||
* An implementation of `submit` that does not dispatch the submission task. | ||
* | ||
@@ -28,4 +32,4 @@ * # Important | ||
submitUndispatched(reason?: string, testResolver?: PromiseCallback): Promise<void>; | ||
private internalSubmit; | ||
submit(reason?: string): void; | ||
submitSync(reason?: string): void; | ||
private internalSubmitSync; | ||
testBeforeNextSubmit(callbackFn: ValidatorFunction): Promise<void>; | ||
@@ -32,0 +36,0 @@ } |
@@ -1,2 +0,2 @@ | ||
import type { StorageIndex } from "../storage/index.js"; | ||
import type { StorageIndex } from "../storage/shared.js"; | ||
import type { JSONObject, JSONValue } from "../utils.js"; | ||
@@ -3,0 +3,0 @@ /** |
@@ -1,2 +0,2 @@ | ||
import EventsDatabase from "../metrics/events_database/index.js"; | ||
import EventsDatabase from "../metrics/events_database/async.js"; | ||
/** | ||
@@ -3,0 +3,0 @@ * Test-only API |
@@ -1,2 +0,2 @@ | ||
import type { QueuedPing } from "./manager"; | ||
import type { QueuedPing } from "./manager/shared.js"; | ||
export declare const enum UploadTaskTypes { | ||
@@ -7,14 +7,14 @@ Done = "done", | ||
} | ||
export declare type Done_UploadTask = { | ||
export type Done_UploadTask = { | ||
type: UploadTaskTypes.Done; | ||
}; | ||
export declare type Wait_UploadTask = { | ||
export type Wait_UploadTask = { | ||
type: UploadTaskTypes.Wait; | ||
remainingTime: number; | ||
}; | ||
export declare type Upload_UploadTask = { | ||
export type Upload_UploadTask = { | ||
type: UploadTaskTypes.Upload; | ||
ping: QueuedPing; | ||
}; | ||
export declare type UploadTask = Done_UploadTask | Wait_UploadTask | Upload_UploadTask; | ||
export type UploadTask = Done_UploadTask | Wait_UploadTask | Upload_UploadTask; | ||
declare const _default: { | ||
@@ -21,0 +21,0 @@ done: () => Done_UploadTask; |
@@ -19,3 +19,3 @@ export declare const DEFAULT_UPLOAD_TIMEOUT_MS = 10000; | ||
/** | ||
* Uploader abstract class, actualy uploading logic varies per platform. | ||
* Uploader abstract class, actual uploading logic varies per platform. | ||
*/ | ||
@@ -22,0 +22,0 @@ export declare abstract class Uploader { |
import type { MetricType } from "./metrics/index.js"; | ||
export declare type JSONPrimitive = string | number | boolean; | ||
export declare type JSONValue = JSONPrimitive | JSONObject | JSONArray; | ||
export declare type JSONObject = { | ||
export type JSONPrimitive = string | number | boolean; | ||
export type JSONValue = JSONPrimitive | JSONObject | JSONArray; | ||
export type JSONObject = { | ||
[member: string]: JSONValue | undefined; | ||
}; | ||
export declare type JSONArray = JSONValue[]; | ||
export type JSONArray = JSONValue[]; | ||
/** | ||
@@ -72,2 +72,9 @@ * Verifies if a given value is a valid JSONValue. | ||
/** | ||
* Convert a boolean stringified value to a proper boolean. | ||
* | ||
* @param v The value to convert. | ||
* @returns A boolean representing the string or undefined if the string was not a boolean value. | ||
*/ | ||
export declare function extractBooleanFromString(v: string): boolean | undefined; | ||
/** | ||
* Generates a pipeline-friendly string | ||
@@ -129,2 +136,15 @@ * that replaces non alphanumeric characters with dashes. | ||
/** | ||
* Truncates a string to a given max length SYNCHRONOUSLY. | ||
* | ||
* If the string required truncation, records an error through the error | ||
* reporting mechanism. | ||
* | ||
* @param metric The metric to record an error to, if necessary, | ||
* @param value The string to truncate. | ||
* @param length The length to truncate to. | ||
* @returns A string with at most `length` bytes. | ||
* @throws In case `value` is not a string. | ||
*/ | ||
export declare function truncateStringAtBoundaryWithErrorSync(metric: MetricType, value: unknown, length: number): string; | ||
/** | ||
* Decorator factory that will only allow a function to be called when Glean is in testing mode. | ||
@@ -151,1 +171,10 @@ * | ||
export declare function getCurrentTimeInNanoSeconds(): number; | ||
/** | ||
* Checks if the current environment has access to the `window` object. This | ||
* check is used to conditional-ize browser code for SSR projects. If the | ||
* platform does not have access to the `window` APIs, then we are unable to | ||
* store data in the browser. | ||
* | ||
* @returns Whether or not the current platform has access to the `window` object. | ||
*/ | ||
export declare function isWindowObjectUnavailable(): boolean; |
export { default as Uploader, UploadResult, UploadResultStatus } from "../core/upload/uploader.js"; | ||
declare const _default: { | ||
initialize(applicationId: string, uploadEnabled: boolean, config?: import("../core/config.js").ConfigurationInterface | undefined): void; | ||
setUploadEnabled(flag: boolean): void; | ||
setLogPings(flag: boolean): void; | ||
setDebugViewTag(value: string): void; | ||
shutdown(): Promise<void>; | ||
setSourceTags(value: string[]): void; | ||
}; | ||
declare const _default: import("./base/shared.js").IGlean; | ||
export default _default; |
@@ -1,3 +0,3 @@ | ||
import type Platform from "../../index.js"; | ||
declare const WebPlaftorm: Platform; | ||
export default WebPlaftorm; | ||
import type PlatformSync from "../../sync.js"; | ||
declare const WebPlatform: PlatformSync; | ||
export default WebPlatform; |
@@ -1,3 +0,3 @@ | ||
import type PlatformInfo from "../../../core/platform_info.js"; | ||
declare const BrowserPlatformInfo: PlatformInfo; | ||
import type PlatformInfoSync from "../../../core/platform_info/sync.js"; | ||
declare const BrowserPlatformInfo: PlatformInfoSync; | ||
export default BrowserPlatformInfo; |
@@ -1,12 +0,12 @@ | ||
import type { StorageIndex } from "../../../core/storage/index.js"; | ||
import type Store from "../../../core/storage/index.js"; | ||
import type SynchronousStore from "../../../core/storage/sync.js"; | ||
import type { StorageIndex } from "../../../core/storage/shared.js"; | ||
import type { JSONValue } from "../../../core/utils.js"; | ||
declare class WebStore implements Store { | ||
declare class WebStore implements SynchronousStore { | ||
private rootKey; | ||
private logTag; | ||
constructor(rootKey: string); | ||
get(index?: StorageIndex): Promise<JSONValue | undefined>; | ||
update(index: StorageIndex, transformFn: (v?: JSONValue) => JSONValue): Promise<void>; | ||
delete(index: StorageIndex): Promise<void>; | ||
get(index?: StorageIndex): JSONValue | undefined; | ||
update(index: StorageIndex, transformFn: (v?: JSONValue) => JSONValue): void; | ||
delete(index: StorageIndex): void; | ||
} | ||
export default WebStore; |
@@ -1,3 +0,3 @@ | ||
import type Platform from "../index.js"; | ||
import type Platform from "../async.js"; | ||
declare const TestPlatform: Platform; | ||
export default TestPlatform; |
@@ -1,3 +0,3 @@ | ||
import type { StorageIndex } from "../../core/storage/index.js"; | ||
import type Store from "../../core/storage/index.js"; | ||
import type { StorageIndex } from "../../core/storage/shared.js"; | ||
import type Store from "../../core/storage/async.js"; | ||
import type { JSONValue } from "../../core/utils.js"; | ||
@@ -4,0 +4,0 @@ /** |
@@ -5,3 +5,3 @@ import type { JWK } from "jose"; | ||
import type { JSONObject } from "../core/utils.js"; | ||
import CoreEvents from "../core/events/index.js"; | ||
import CoreEvents from "../core/events/async.js"; | ||
/** | ||
@@ -19,3 +19,3 @@ * A plugin that listens for the `afterPingCollection` event and encrypts **all** outgoing pings | ||
*/ | ||
declare class PingEncryptionPlugin extends Plugin<typeof CoreEvents["afterPingCollection"]> { | ||
declare class PingEncryptionPlugin extends Plugin<(typeof CoreEvents)["afterPingCollection"]> { | ||
private jwk; | ||
@@ -22,0 +22,0 @@ /** |
@@ -1,4 +0,4 @@ | ||
import type { CoreEvent } from "../core/events/index.js"; | ||
export declare type EventContext<Context> = Context extends CoreEvent<infer InnerContext, unknown> ? InnerContext : undefined[]; | ||
export declare type EventResult<Result> = Result extends CoreEvent<unknown[], infer InnerResult> ? InnerResult : void; | ||
import type { CoreEvent } from "../core/events/shared.js"; | ||
export type EventContext<Context> = Context extends CoreEvent<infer InnerContext, unknown> ? InnerContext : undefined[]; | ||
export type EventResult<Result> = Result extends CoreEvent<unknown[], infer InnerResult> ? InnerResult : void; | ||
/** | ||
@@ -5,0 +5,0 @@ * Plugins can listen to events that happen during Glean's lifecycle. |
{ | ||
"name": "@mozilla/glean", | ||
"version": "1.3.0", | ||
"version": "3.0.0", | ||
"description": "An implementation of the Glean SDK, a modern cross-platform telemetry client, for JavaScript environments.", | ||
@@ -15,4 +15,2 @@ "type": "module", | ||
"./testing": "./dist/core/testing/index.js", | ||
"./node": "./dist/entry/node.js", | ||
"./webext": "./dist/entry/webext.js", | ||
"./web": "./dist/entry/web.js" | ||
@@ -22,8 +20,2 @@ }, | ||
"*": { | ||
"webext": [ | ||
"./dist/types/entry/webext.d.ts" | ||
], | ||
"node": [ | ||
"./dist/types/entry/node.d.ts" | ||
], | ||
"web": [ | ||
@@ -63,3 +55,3 @@ "./dist/types/entry/web.d.ts" | ||
"test:integration": "npm run test:base -- \"tests/integration/**/*.spec.ts\" --recursive", | ||
"pretest:integration": "../bin/parser-for-schema-testing.sh", | ||
"pretest:integration": "../bin/parser-for-schema-testing.sh && ../bin/python-env-vars-test.sh", | ||
"test:unit": "run-s test:unit:core test:unit:platform test:unit:plugins", | ||
@@ -69,3 +61,2 @@ "test:unit:core": "npm run test:base -- \"tests/unit/core/**/*.spec.ts\" --recursive", | ||
"test:unit:platform": "npm run test:base -- \"tests/unit/platform/**/*.spec.ts\" --recursive --timeout 0", | ||
"pretest:unit:platform": "cd tests/unit/platform/utils/webext/sample/ && npm install && npm run build:xpi", | ||
"test:base": "node --experimental-modules --experimental-specifier-resolution=node --loader=ts-node/esm node_modules/mocha/lib/cli/cli.js", | ||
@@ -77,9 +68,7 @@ "lint": "run-s lint:eslint lint:circular-deps lint:glinter", | ||
"fix": "eslint . --ext .ts,.js,.json --fix", | ||
"build": "run-s build:no-qt build:qt", | ||
"build:no-qt": "rm -rf dist && run-s build:cli build:lib build:types", | ||
"build": "rimraf dist && run-s build:cli build:lib build:types", | ||
"build:cli": "tsc -p ./tsconfig/cli.json", | ||
"build:lib": "tsc -p ./tsconfig/lib.json", | ||
"build:types": "tsc -p ./tsconfig/types.json", | ||
"build:qt": "rm -rf dist/qt && webpack --config webpack.config.qt.js && ../bin/prepare-qml-module.sh", | ||
"build:docs": "rm -rf dist/docs && typedoc --entryPointStrategy expand ./src --out dist/docs --tsconfig tsconfig/docs.json", | ||
"build:docs": "rimraf dist/docs && typedoc --entryPointStrategy expand ./src --out dist/docs --tsconfig tsconfig/docs.json", | ||
"build:metrics-docs": "npm run cli -- translate src/metrics.yaml src/pings.yaml -o ../docs/reference/ --format markdown --allow-reserved", | ||
@@ -111,8 +100,7 @@ "publish:docs": "NODE_DEBUG=gh-pages gh-pages --dotfiles --message \"[skip ci] Updates\" --dist dist/docs", | ||
"@types/sinon": "^10.0.0", | ||
"@types/sqlite3": "^3.1.7", | ||
"@types/uuid": "^8.3.1", | ||
"@types/uuid": "^9.0.1", | ||
"@typescript-eslint/eslint-plugin": "^5.0.0", | ||
"@typescript-eslint/parser": "^5.0.0", | ||
"eslint": "^8.0.1", | ||
"eslint-plugin-import": "2.26.0", | ||
"eslint-plugin-import": "2.29.0", | ||
"eslint-plugin-jsdoc": "^39.2.9", | ||
@@ -123,8 +111,8 @@ "eslint-plugin-json": "^3.0.0", | ||
"fake-indexeddb": "^4.0.0", | ||
"geckodriver": "^3.0.1", | ||
"gh-pages": "^4.0.0", | ||
"jsdom": "20.0.1", | ||
"geckodriver": "^4.1.3", | ||
"gh-pages": "^6.0.0", | ||
"jsdom": "22.1.0", | ||
"jsdom-global": "3.0.2", | ||
"jsonschema": "^1.4.0", | ||
"madge": "^5.0.1", | ||
"madge": "^6.1.0", | ||
"mocha": "^10.0.0", | ||
@@ -136,5 +124,5 @@ "nock": "^13.1.3", | ||
"request-promise-native": "^1.0.9", | ||
"rimraf": "^5.0.0", | ||
"selenium-webdriver": "^4.0.0-alpha.8", | ||
"sinon": "^14.0.0", | ||
"sqlite3": "^5.0.2", | ||
"sinon": "^15.0.1", | ||
"terser-webpack-plugin": "^5.2.4", | ||
@@ -144,10 +132,10 @@ "ts-loader": "^9.0.1", | ||
"ts-node": "^10.8.0", | ||
"typedoc": "^0.23.11", | ||
"typedoc": "^0.25.1", | ||
"typescript": "^4.3.5", | ||
"web-ext-types": "^3.2.1", | ||
"webpack": "^5.42.1", | ||
"webpack-cli": "^4.5.0" | ||
"webpack-cli": "^5.0.1" | ||
}, | ||
"dependencies": { | ||
"fflate": "^0.7.1", | ||
"fflate": "^0.8.0", | ||
"jose": "^4.0.4", | ||
@@ -154,0 +142,0 @@ "tslib": "^2.3.1", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
459047
39
202
11773
2
7
+ Addedfflate@0.8.2(transitive)
- Removedfflate@0.7.4(transitive)
Updatedfflate@^0.8.0