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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
[Full changelog](https://github.com/mozilla/glean.js/compare/v0.3.0...main)

* [#92](https://github.com/mozilla/glean.js/pull/92): Remove `web-ext-types` from `peerDependencies` list.
* [#98](https://github.com/mozilla/glean.js/pull/98): Add external APIs for setting the Debug View Tag and Source Tags.
* [#99](https://github.com/mozilla/glean.js/pull/99): BUGFIX: Add a default ping value in the testing APIs.

# v0.3.0 (2021-02-24)
Expand Down
55 changes: 51 additions & 4 deletions glean/src/core/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@
* 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 { DEFAULT_TELEMETRY_ENDPOINT } from "./constants";
import { DEFAULT_TELEMETRY_ENDPOINT, GLEAN_MAX_SOURCE_TAGS } from "./constants";
import Plugin from "../plugins";
import { validateURL } from "./utils";
import { validateHeader, validateURL } from "./utils";

/**
* Lists Glean's debug options.
*/
interface DebugOptions {
// Whether or not lot log pings when they are collected.
logPings?: boolean,
// The value of the X-Debug-ID header to be included in every ping.
debugViewTag?: string,
// The value of the X-Source-Tags header to be included in every ping.
sourceTags?: string[],
}

/**
Expand All @@ -38,12 +42,13 @@ export class Configuration implements ConfigurationInterface {
// The server pings are sent to.
readonly serverEndpoint: string;
// Debug configuration.
debug?: DebugOptions;
debug: DebugOptions;

constructor(config?: ConfigurationInterface) {
this.appBuild = config?.appBuild;
this.appDisplayVersion = config?.appDisplayVersion;
this.debug = config?.debug;

this.debug = Configuration.sanitizeDebugOptions(config?.debug);

if (config?.serverEndpoint && !validateURL(config.serverEndpoint)) {
throw new Error(
Expand All @@ -52,4 +57,46 @@ export class Configuration implements ConfigurationInterface {
this.serverEndpoint = (config && config.serverEndpoint)
? config.serverEndpoint : DEFAULT_TELEMETRY_ENDPOINT;
}

static sanitizeDebugOptions(debug?: DebugOptions): DebugOptions {
const correctedDebugOptions: DebugOptions = debug || {};
if (!Configuration.validateDebugViewTag(debug?.debugViewTag || "")) {
delete correctedDebugOptions["debugViewTag"];
}
if (!Configuration.validateSourceTags(debug?.sourceTags || [])) {
delete correctedDebugOptions["sourceTags"];
}
return correctedDebugOptions;
}

static validateDebugViewTag(tag: string): boolean {
const validation = validateHeader(tag);
if (!validation) {
console.error(
`"${tag}" is not a valid \`debugViewTag\` value.`,
"Please make sure the value passed satisfies the regex `^[a-zA-Z0-9-]{1,20}$`."
);
}
return validation;
}

static validateSourceTags(tags: string[]): boolean {
if (tags.length < 1 || tags.length > GLEAN_MAX_SOURCE_TAGS) {
console.error(`A list of tags cannot contain more than ${GLEAN_MAX_SOURCE_TAGS} elements.`);
return false;
}

for (const tag of tags) {
if (tag.startsWith("glean")) {
console.error("Tags starting with `glean` are reserved and must not be used.");
return false;
}

if (!validateHeader(tag)) {
return false;
}
}

return true;
}
}
3 changes: 3 additions & 0 deletions glean/src/core/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,6 @@ export const DEFAULT_TELEMETRY_ENDPOINT = "https://incoming.telemetry.mozilla.or

// The name of the deletion-request ping.
export const DELETION_REQUEST_PING_NAME = "deletion-request";

// The maximum amount of source tags a user can set.
export const GLEAN_MAX_SOURCE_TAGS = 5;
96 changes: 87 additions & 9 deletions glean/src/core/glean.ts
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,14 @@ class Glean {
return Glean.instance._config?.debug?.logPings || false;
}

static get debugViewTag(): string | undefined {
return Glean.instance._config?.debug.debugViewTag;
}

static get sourceTags(): string | undefined {
return Glean.instance._config?.debug.sourceTags?.toString();
}

static get dispatcher(): Dispatcher {
return Glean.instance._dispatcher;
}
Expand Down Expand Up @@ -399,31 +407,101 @@ class Glean {
}

/**
* Sets the `logPings` flag.
* Sets the `logPings` debug option.
*
* When this flag is `true` pings will be logged to the console right before they are collected.
*
* @param flag Whether or not to log pings.
*/
static setLogPings(flag: boolean): void {
Glean.dispatcher.launch(() => {
// It is guaranteed that _config will have a value here.
//
// All dispatched tasks are guaranteed to be run after initialize.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
if (!Glean.instance._config!.debug) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
Glean.instance._config!.debug = {};
}
Glean.instance._config!.debug.logPings = flag;

// The dispatcher requires that dispatched functions return promises.
return Promise.resolve();
});
}

/**
* Sets the `debugViewTag` debug option.
*
* When this property is set, all subsequent outgoing pings will include the `X-Debug-ID` header
* which will redirect them to the ["Ping Debug Viewer"](https://debug-ping-preview.firebaseapp.com/).
*
* To unset the `debugViewTag` call `Glean.unsetDebugViewTag();
*
* @param value The value of the header.
* This value must satify the regex `^[a-zA-Z0-9-]{1,20}$` otherwise it will be ignored.
*/
static setDebugViewTag(value: string): void {
if (!Configuration.validateDebugViewTag(value)) {
console.error(`Invalid \`debugViewTag\` ${value}. Ignoring.`);
return;
}

Glean.dispatcher.launch(() => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
Glean.instance._config!.debug.logPings = flag;
Glean.instance._config!.debug.debugViewTag = value;

// The dispatcher requires that dispatched functions return promises.
return Promise.resolve();
});
}

/**
* Unsets the `debugViewTag` debug option.
*
* This is a no-op is case there is no `debugViewTag` set at the moment.
*/
static unsetDebugViewTag(): void {
Glean.dispatcher.launch(() => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
delete Glean.instance._config!.debug.debugViewTag;
return Promise.resolve();
});
}

/**
* Sets the `sourceTags` debug option.
*
* Ping tags will show in the destination datasets, after ingestion.
*
* **Note** Setting `sourceTags` will override all previously set tags.
*
* To unset the `sourceTags` call `Glean.unsetSourceTags();
*
* @param value A vector of at most 5 valid HTTP header values.
* Individual tags must match the regex: "[a-zA-Z0-9-]{1,20}".
*/
static setSourceTags(value: string[]): void {
if (!Configuration.validateSourceTags(value)) {
console.error(`Invalid \`sourceTags\` ${value.toString()}. Ignoring.`);
return;
}

Glean.dispatcher.launch(() => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
Glean.instance._config!.debug.sourceTags = value;

// The dispatcher requires that dispatched functions return promises.
return Promise.resolve();
});
}

/**
* Unsets the `sourceTags` debug option.
*
* This is a no-op is case there are no `sourceTags` set at the moment.
*/
static unsetSourceTags(): void {
Glean.dispatcher.launch(() => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
delete Glean.instance._config!.debug.sourceTags;
return Promise.resolve();
});
}

/**
* Sets the current environment.
*
Expand Down
20 changes: 17 additions & 3 deletions glean/src/core/pings/maker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,12 +148,26 @@ export async function buildClientInfoSection(ping: PingType): Promise<ClientInfo
* ping submission will still contain the desired headers.
*
* The current headers gathered here are:
* - [X-Debug-Id]
* - [X-Debug-ID]
* - [X-Source-Tags]
*
* @returns An object containing all the headers and their values
* or `undefined` in case no custom headers were set.
*/
export function getPingHeaders(): Record<string, string> | undefined {
// TODO: Returning nothing for now until Bug 1685718 is resolved.
return;
const headers: Record<string, string> = {};

if (Glean.debugViewTag) {
headers["X-Debug-ID"] = Glean.debugViewTag;
}

if (Glean.sourceTags) {
headers["X-Source-Tags"] = Glean.sourceTags;
}

if (Object.keys(headers).length > 0) {
return headers;
}
}

/**
Expand Down
11 changes: 11 additions & 0 deletions glean/src/core/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,17 @@ export function validateURL(v: string): boolean {
return urlPattern.test(v);
}

/**
* Validates whether or not a given value is an acceptable HTTP header for outgoing pings.
*
* @param v The value to validate.
*
* @returns Whether or not the given value is a valid HTTP header value.
*/
export function validateHeader(v: string): boolean {
return /^[a-z0-9-]{1,20}$/i.test(v);
}

/**
* Generates a UUIDv4.
*
Expand Down
49 changes: 49 additions & 0 deletions glean/src/index/qt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,55 @@ export default {
Glean.setLogPings(flag);
},

/**
* Sets the `debugViewTag` debug option.
*
* When this property is set, all subsequent outgoing pings will include the `X-Debug-ID` header
* which will redirect them to the ["Ping Debug Viewer"](https://debug-ping-preview.firebaseapp.com/).
*
* To unset the `debugViewTag` call `Glean.unsetDebugViewTag();
*
* @param value The value of the header.
* This value must satify the regex `^[a-zA-Z0-9-]{1,20}$` otherwise it will be ignored.
*/
setDebugViewTag(value: string): void {
Glean.setDebugViewTag(value);
},

/**
* Unsets the `debugViewTag` debug option.
*
* This is a no-op is case there is no `debugViewTag` set at the moment.
*/
unsetDebugViewTag(): void {
Glean.unsetDebugViewTag();
},

/**
* Sets the `sourceTags` debug option.
*
* Ping tags will show in the destination datasets, after ingestion.
*
* **Note** Setting `sourceTags` will override all previously set tags.
*
* To unset the `sourceTags` call `Glean.unsetSourceTags();
*
* @param value A vector of at most 5 valid HTTP header values.
* Individual tags must match the regex: "[a-zA-Z0-9-]{1,20}".
*/
setSourceTags(value: string[]): void {
Glean.setSourceTags(value);
},

/**
* Unsets the `sourceTags` debug option.
*
* This is a no-op is case there are no `sourceTags` set at the moment.
*/
unsetSourceTags(): void {
Glean.unsetSourceTags();
},

_private: {
PingType,
BooleanMetricType,
Expand Down
53 changes: 51 additions & 2 deletions glean/src/index/webext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export default {
},

/**
* Sets the `logPings` flag.
* Sets the `logPings` debug option.
*
* When this flag is `true` pings will be logged
* to the console right before they are collected.
Expand All @@ -63,5 +63,54 @@ export default {
*/
setLogPings(flag: boolean): void {
Glean.setLogPings(flag);
}
},

/**
* Sets the `debugViewTag` debug option.
*
* When this property is set, all subsequent outgoing pings will include the `X-Debug-ID` header
* which will redirect them to the ["Ping Debug Viewer"](https://debug-ping-preview.firebaseapp.com/).
*
* To unset the `debugViewTag` call `Glean.unsetDebugViewTag();
*
* @param value The value of the header.
* This value must satify the regex `^[a-zA-Z0-9-]{1,20}$` otherwise it will be ignored.
*/
setDebugViewTag(value: string): void {
Glean.setDebugViewTag(value);
},

/**
* Unsets the `debugViewTag` debug option.
*
* This is a no-op is case there is no `debugViewTag` set at the moment.
*/
unsetDebugViewTag(): void {
Glean.unsetDebugViewTag();
},

/**
* Sets the `sourceTags` debug option.
*
* Ping tags will show in the destination datasets, after ingestion.
*
* **Note** Setting `sourceTags` will override all previously set tags.
*
* To unset the `sourceTags` call `Glean.unsetSourceTags();
*
* @param value A vector of at most 5 valid HTTP header values.
* Individual tags must match the regex: "[a-zA-Z0-9-]{1,20}".
*/
setSourceTags(value: string[]): void {
Glean.setSourceTags(value);
},

/**
* Unsets the `sourceTags` debug option.
*
* This is a no-op is case there are no `sourceTags` set at the moment.
*/
unsetSourceTags(): void {
Glean.unsetSourceTags();
},
};
Loading