Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import { version } from "../package.json";

export const GLEAN_SCHEMA_VERSION = 1;

// The version for the current build of Glean.js
//
// PACKAGE_VERSION is defined as a global by webpack,
// we need a default here for testing when the app is not build with webpack.
export const GLEAN_VERSION = version;

// The name of a "ping" that will include Glean ping_info metrics,
// such as ping sequence numbers.
//
// Note that this is not really a ping,
// but a neat way to gather metrics in the metrics database.
//
// See: https://mozilla.github.io/glean/book/dev/core/internal/reserved-ping-names.html
export const PING_INFO_STORAGE = "glean_ping_info";

// The name of a "ping" that will include the Glean client_info metrics,
// such as ping sequence numbers.
//
// Note that this is not really a ping,
// but a neat way to gather metrics in the metrics database.
//
// See: https://mozilla.github.io/glean/book/dev/core/internal/reserved-ping-names.html
export const CLIENT_INFO_STORAGE = "glean_client_info";
67 changes: 58 additions & 9 deletions src/glean.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,26 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import Database from "database";
import { isUndefined } from "utils";
import MetricsDatabase from "metrics/database";
import PingsDatabase from "pings/database";
import { isUndefined, sanitizeApplicationId } from "utils";

class Glean {
// The Glean singleton.
private static _instance?: Glean;

// The metrics database.
private _db: Database;
// The metrics and pings databases.
private _db: {
metrics: MetricsDatabase,
pings: PingsDatabase
}
// Whether or not to record metrics.
private _uploadEnabled: boolean;
// Whether or not Glean has been initialized.
private _initialized: boolean;

// Properties that will only be set on `initialize`.
private _applicationId?: string;

private constructor() {
if (!isUndefined(Glean._instance)) {
Expand All @@ -21,7 +30,11 @@ class Glean {
Use Glean.instance instead to access the Glean singleton.`);
}

this._db = new Database();
this._initialized = false;
this._db = {
metrics: new MetricsDatabase(),
pings: new PingsDatabase()
};
// Temporarily setting this to true always, until Bug 1677444 is resolved.
this._uploadEnabled = true;
}
Expand All @@ -34,9 +47,36 @@ class Glean {
return Glean._instance;
}

/**
* Initialize Glean. This method should only be called once, subsequent calls will be no-op.
*
* @param applicationId The application ID (will be sanitized during initialization).
*/
static initialize(applicationId: string): void {
if (Glean.instance._initialized) {
console.warn("Attempted to initialize Glean, but it has already been initialized. Ignoring.");
return;
}

Glean.instance._applicationId = sanitizeApplicationId(applicationId);
}

/**
* Gets this Glean's instance metrics database.
*
* @returns This Glean's instance metrics database.
*/
static get metricsDatabase(): MetricsDatabase {
return Glean.instance._db.metrics;
}

static get db(): Database {
return Glean.instance._db;
/**
* Gets this Glean's instance pings database.
*
* @returns This Glean's instance pings database.
*/
static get pingsDatabase(): PingsDatabase {
return Glean.instance._db.pings;
}

// TODO: Make the following functions `private` once Bug 1682769 is resolved.
Expand All @@ -48,6 +88,14 @@ class Glean {
Glean.instance._uploadEnabled = value;
}

static get applicationId(): string | undefined {
if (!Glean.instance._initialized) {
console.error("Attempted to access the Glean.applicationId before Glean was initialized.");
}

return Glean.instance._applicationId;
}

/**
* **Test-only API**
*
Expand All @@ -58,8 +106,9 @@ class Glean {
static async testRestGlean(): Promise<void> {
// Reset upload enabled state, not to inerfere with other tests.
Glean.uploadEnabled = true;
// Clear the database.
await Glean.db.clearAll();
// Clear the databases.
await Glean.metricsDatabase.clearAll();
await Glean.pingsDatabase.clearAll();
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/database.ts → src/metrics/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ function createMetricsPayload(v: Metrics): Metrics {
* We have one store in this format for each lifetime: user, ping and application.
*
*/
class Database {
class MetricsDatabase {
private userStore: Store;
private pingStore: Store;
private appStore: Store;
Expand Down Expand Up @@ -221,7 +221,7 @@ class Database {
* @returns An object containing all the metrics recorded to the given ping,
* `undefined` in case the ping doesn't contain any recorded metrics.
*/
async getPing(ping: string, clearPingLifetimeData: boolean): Promise<Metrics | undefined> {
async getPingMetrics(ping: string, clearPingLifetimeData: boolean): Promise<Metrics | undefined> {
const userData = await this.getAndValidatePingData(ping, Lifetime.User);
const pingData = await this.getAndValidatePingData(ping, Lifetime.Ping);
const appData = await this.getAndValidatePingData(ping, Lifetime.Application);
Expand Down Expand Up @@ -267,4 +267,4 @@ class Database {
}
}

export default Database;
export default MetricsDatabase;
4 changes: 2 additions & 2 deletions src/metrics/boolean.ts → src/metrics/types/boolean.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class BooleanMetricType extends MetricType {
}

const metric = new BooleanMetric(value);
await Glean.db.record(this, metric);
await Glean.metricsDatabase.record(this, metric);
}

/**
Expand All @@ -57,7 +57,7 @@ class BooleanMetricType extends MetricType {
* @returns The value found in storage or `undefined` if nothing was found.
*/
async testGetValue(ping: string): Promise<boolean | undefined> {
return Glean.db.getMetric<boolean>(ping, this);
return Glean.metricsDatabase.getMetric<boolean>(ping, this);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/metrics/counter.ts → src/metrics/types/counter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class CounterMetricType extends MetricType {
};
})(amount);

await Glean.db.transform(this, transformFn);
await Glean.metricsDatabase.transform(this, transformFn);
}

/**
Expand All @@ -104,7 +104,7 @@ class CounterMetricType extends MetricType {
* @returns The value found in storage or `undefined` if nothing was found.
*/
async testGetValue(ping: string): Promise<number | undefined> {
return Glean.db.getMetric<number>(ping, this);
return Glean.metricsDatabase.getMetric<number>(ping, this);
}
}

Expand Down
18 changes: 11 additions & 7 deletions src/metrics/datetime.ts → src/metrics/types/datetime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ export class DatetimeMetric extends Metric<DatetimeInternalRepresentation, strin
super(v);
}

static fromDate(v: Date, timeUnit: TimeUnit): DatetimeMetric {
return new DatetimeMetric({
timeUnit,
timezone: v.getTimezoneOffset(),
date: v.toISOString()
});
}

/**
* Gets the datetime data as a Date object.
*
Expand Down Expand Up @@ -198,12 +206,8 @@ class DatetimeMetricType extends MetricType {
break;
}

const metric = new DatetimeMetric({
timeUnit: this.timeUnit,
timezone: value.getTimezoneOffset(),
date: value.toISOString(),
});
await Glean.db.record(this, metric);
const metric = DatetimeMetric.fromDate(value, this.timeUnit);
await Glean.metricsDatabase.record(this, metric);
}

/**
Expand All @@ -220,7 +224,7 @@ class DatetimeMetricType extends MetricType {
* @returns The value found in storage or `undefined` if nothing was found.
*/
private async testGetValueAsDatetimeMetric(ping: string): Promise<DatetimeMetric | undefined> {
const value = await Glean.db.getMetric<DatetimeInternalRepresentation>(ping, this);
const value = await Glean.metricsDatabase.getMetric<DatetimeInternalRepresentation>(ping, this);
if (value) {
return new DatetimeMetric(value);
}
Expand Down
4 changes: 2 additions & 2 deletions src/metrics/string.ts → src/metrics/types/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class StringMetricType extends MetricType {
}

const metric = new StringMetric(value.substr(0, MAX_LENGTH_VALUE));
await Glean.db.record(this, metric);
await Glean.metricsDatabase.record(this, metric);
}

/**
Expand All @@ -79,7 +79,7 @@ class StringMetricType extends MetricType {
* @returns The value found in storage or `undefined` if nothing was found.
*/
async testGetValue(ping: string): Promise<string | undefined> {
return Glean.db.getMetric<string>(ping, this);
return Glean.metricsDatabase.getMetric<string>(ping, this);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/metrics/uuid.ts → src/metrics/types/uuid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class UUIDMetricType extends MetricType {
return;
}

await Glean.db.record(this, metric);
await Glean.metricsDatabase.record(this, metric);
}

/**
Expand Down Expand Up @@ -94,7 +94,7 @@ class UUIDMetricType extends MetricType {
* @returns The value found in storage or `undefined` if nothing was found.
*/
async testGetValue(ping: string): Promise<string | undefined> {
return Glean.db.getMetric<string>(ping, this);
return Glean.metricsDatabase.getMetric<string>(ping, this);
}
}

Expand Down
10 changes: 5 additions & 5 deletions src/metrics/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
import { Metric } from "metrics";
import { JSONValue } from "utils";

import { BooleanMetric } from "metrics/boolean";
import { CounterMetric } from "metrics/counter";
import { StringMetric } from "metrics/string";
import { UUIDMetric } from "metrics/uuid";
import { DatetimeMetric } from "./datetime";
import { BooleanMetric } from "metrics/types/boolean";
import { CounterMetric } from "metrics/types/counter";
import { StringMetric } from "metrics/types/string";
import { UUIDMetric } from "metrics/types/uuid";
import { DatetimeMetric } from "./types/datetime";

/**
* A map containing all supported internal metrics and its constructors.
Expand Down
Loading