firestore-metrics
Version:
A library which uses the Cloud Monitoring API v3 to view Firestore metrics.
311 lines • 13.9 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FirestoreMetrics = void 0;
const google_auth_library_1 = require("google-auth-library");
class FirestoreMetrics {
constructor(params) {
var _a;
this.projectId = null;
this.accessToken = null;
this.googleAuth = null;
this.baseUrl = "https://monitoring.googleapis.com/v3/projects";
this.scopes = [
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/monitoring",
"https://www.googleapis.com/auth/monitoring.read",
];
this.googleAuthArgs = Object.assign({}, params);
this.projectId = (_a = params.projectId) !== null && _a !== void 0 ? _a : null;
}
/**
* Helper function to compose the metric type filter.
* @param {string} metricName Name of the metric type.
* @returns {string} A string filter to be passed to the request.
*/
metricFilter(metricName) {
const encodedMetricName = encodeURI(metricName);
return `filter=metric.type%20%3D%20%22firestore.googleapis.com%2F${encodedMetricName}%22`;
}
/**
* Creates a Google Auth instance if null.
*/
createGoogleAuthInstance() {
if (this.googleAuth === null) {
this.googleAuth = new google_auth_library_1.GoogleAuth(Object.assign(Object.assign({}, this.googleAuthArgs), { scopes: this.scopes }));
}
}
/**
* Gets the project ID and sets its value if it is still null.
*/
getProjectId() {
return __awaiter(this, void 0, void 0, function* () {
this.createGoogleAuthInstance();
this.projectId = this.projectId || (yield this.googleAuth.getProjectId());
return this.projectId;
});
}
/**
* Generates an access token.
* @param {boolean} overwriteExisting If true, overwrites the existing access token.
* @returns {Promise<string>} Access token used to authenticate requests.
*/
generateToken(overwriteExisting = true) {
return __awaiter(this, void 0, void 0, function* () {
if (this.accessToken === null || overwriteExisting === true) {
this.createGoogleAuthInstance();
this.accessToken = yield this.googleAuth.getAccessToken();
}
// Makes sure that the project id is always loaded before being used.
yield this.getProjectId();
return this.accessToken;
});
}
/**
* Sets the access token.
* @param {boolean} accessToken Value of the new access token.
*/
setAccessToken(accessToken) {
this.accessToken = accessToken;
return;
}
/**
* Makes a request to the Cloud monitoring API.
* @param {string} filter A monitoring filter that specifies which time series should be returned.
* @param {string} startTime The beginning of the time interval.
* @param {string} endTime The end of the time interval.
* @returns
*/
makeRequest(filter, startTime, endTime) {
return __awaiter(this, void 0, void 0, function* () {
const encodedStartTime = encodeURI(startTime);
const encodedEndTime = encodeURI(endTime);
const timeInterval = `interval.endTime=${encodedEndTime}&interval.startTime=${encodedStartTime}`;
const url = `${this.baseUrl}/${this.projectId}/timeSeries?${filter}&${timeInterval}`;
const response = yield fetch(url, {
headers: {
accept: "*/*",
authorization: `Bearer ${this.accessToken}`,
},
body: null,
method: "GET",
});
if (response.status !== 200) {
const errMesage = yield response.text();
throw Error(errMesage);
}
return response;
});
}
/**
* Check if the list contains an the object.
* @param obj Object.
* @param list List of objects.
* @returns True if the list contains the object.
*/
containsObject(obj, list) {
if (JSON.stringify(list).includes(JSON.stringify(obj))) {
return true;
}
return false;
}
/**
* Removes keys in an object with null, undefined, etc. value.
* @param obj Object.
* @param args Additional values to be removes.
* @returns An object with keys with invalid values removed.
*/
cleanObject(obj, ...args) {
const invalidValues = [null, undefined, ...args];
for (let propName in obj) {
if (invalidValues.includes(obj[propName])) {
delete obj[propName];
}
}
return obj;
}
/**
* Cleans/formats the response into something more understandable.
* @param {Response} response Fetch response.
* @returns {Promise<Array<TimeIntervalMetric>>} An array of time intervals and count of transactions for that time.
*/
cleanResponseTimeSeries(response) {
return __awaiter(this, void 0, void 0, function* () {
const cleanTimeSeries = [];
const responseContent = yield response.text();
const timeSeriesResponse = JSON.parse(responseContent);
if (timeSeriesResponse.timeSeries === undefined) {
return cleanTimeSeries;
}
for (let timeSeries of timeSeriesResponse.timeSeries) {
for (let point of timeSeries.points) {
if (point.value.int64Value !== "0") {
const labels = this.cleanObject(timeSeries.metric.labels, "__unknown__", "");
const pointMetric = Object.assign(Object.assign({}, labels), { interval: {
endTime: point.interval.endTime,
startTime: point.interval.startTime,
}, count: parseInt(point.value.int64Value) });
if (!this.containsObject(pointMetric, cleanTimeSeries)) {
cleanTimeSeries.push(pointMetric);
}
}
}
}
return cleanTimeSeries;
});
}
/**
* Get Firestore read count metrics.
* @param {DateTimeStringISO} startTime The beginning of the time interval.
* @param {DateTimeStringISO} endTime The end of the time interval.
* @param {string?} accessToken Access token used to authenticate.
* @returns {Promise<Array<TimeIntervalMetric>>}
*/
getReadCount(startTime, endTime, accessToken = null) {
return __awaiter(this, void 0, void 0, function* () {
if (accessToken === null) {
yield this.generateToken(false);
}
const filter = this.metricFilter("document/read_count");
const res = yield this.makeRequest(filter, startTime, endTime);
const cleanTimeSeries = yield this.cleanResponseTimeSeries(res);
return cleanTimeSeries;
});
}
/**
* Get Firestore write count metrics.
* @param {DateTimeStringISO} startTime The beginning of the time interval.
* @param {DateTimeStringISO} endTime The end of the time interval.
* @param {string?} accessToken Access token used to authenticate.
* @returns {Promise<Array<TimeIntervalMetric>>}
*/
getWriteCount(startTime, endTime, accessToken = null) {
return __awaiter(this, void 0, void 0, function* () {
if (accessToken === null) {
yield this.generateToken(false);
}
const filter = this.metricFilter("document/write_count");
const res = yield this.makeRequest(filter, startTime, endTime);
const cleanTimeSeries = yield this.cleanResponseTimeSeries(res);
return cleanTimeSeries;
});
}
/**
* Get Firestore delete count metrics.
* @param {DateTimeStringISO} startTime The beginning of the time interval.
* @param {DateTimeStringISO} endTime The end of the time interval.
* @param {string?} accessToken Access token used to authenticate.
* @returns {Promise<Array<TimeIntervalMetric>>}
*/
getDeleteCount(startTime, endTime, accessToken = null) {
return __awaiter(this, void 0, void 0, function* () {
if (accessToken === null) {
yield this.generateToken(false);
}
const filter = this.metricFilter("document/delete_count");
const res = yield this.makeRequest(filter, startTime, endTime);
const cleanTimeSeries = yield this.cleanResponseTimeSeries(res);
return cleanTimeSeries;
});
}
/**
* Get Firestore snapshot listeners count metrics.
* @param {DateTimeStringISO} startTime The beginning of the time interval.
* @param {DateTimeStringISO} endTime The end of the time interval.
* @param {string?} accessToken Access token used to authenticate.
* @returns {Promise<Array<TimeIntervalMetric>>}
*/
getSnapshotListeners(startTime, endTime, accessToken = null) {
return __awaiter(this, void 0, void 0, function* () {
if (accessToken === null) {
yield this.generateToken(false);
}
const filter = this.metricFilter("network/snapshot_listeners");
const res = yield this.makeRequest(filter, startTime, endTime);
const cleanTimeSeries = yield this.cleanResponseTimeSeries(res);
return cleanTimeSeries;
});
}
/**
* Get Firestore active connections count metrics.
* @param {DateTimeStringISO} startTime The beginning of the time interval.
* @param {DateTimeStringISO} endTime The end of the time interval.
* @param {string?} accessToken Access token used to authenticate.
* @returns {Promise<Array<TimeIntervalMetric>>}
*/
getActiveConnections(startTime, endTime, accessToken = null) {
return __awaiter(this, void 0, void 0, function* () {
if (accessToken === null) {
yield this.generateToken(false);
}
const filter = this.metricFilter("network/active_connections");
const res = yield this.makeRequest(filter, startTime, endTime);
const cleanTimeSeries = yield this.cleanResponseTimeSeries(res);
return cleanTimeSeries;
});
}
/**
* Get Firestore documents deleted by TTL services count.
* @param {DateTimeStringISO} startTime The beginning of the time interval.
* @param {DateTimeStringISO} endTime The end of the time interval.
* @param {string?} accessToken Access token used to authenticate.
* @returns {Promise<Array<TimeIntervalMetric>>}
*/
getTTLDeletionCount(startTime, endTime, accessToken = null) {
return __awaiter(this, void 0, void 0, function* () {
if (accessToken === null) {
yield this.generateToken(false);
}
const filter = this.metricFilter("document/ttl_deletion_count");
const res = yield this.makeRequest(filter, startTime, endTime);
const cleanTimeSeries = yield this.cleanResponseTimeSeries(res);
return cleanTimeSeries;
});
}
/**
* Get Firestore Security Rule evaluations count performed in response to write read requests.
* @param {DateTimeStringISO} startTime The beginning of the time interval.
* @param {DateTimeStringISO} endTime The end of the time interval.
* @param {string?} accessToken Access token used to authenticate.
* @returns {Promise<Array<TimeIntervalMetric>>}
*/
getRulesEvaluationCount(startTime, endTime, accessToken = null) {
return __awaiter(this, void 0, void 0, function* () {
if (accessToken === null) {
yield this.generateToken(false);
}
const filter = this.metricFilter("rules/evaluation_count");
const res = yield this.makeRequest(filter, startTime, endTime);
const cleanTimeSeries = yield this.cleanResponseTimeSeries(res);
return cleanTimeSeries;
});
}
/**
* Get Firestore API calls count.
* @param {DateTimeStringISO} startTime The beginning of the time interval.
* @param {DateTimeStringISO} endTime The end of the time interval.
* @param {string?} accessToken Access token used to authenticate.
* @returns {Promise<Array<TimeIntervalMetric>>}
*/
getRequestCount(startTime, endTime, accessToken = null) {
return __awaiter(this, void 0, void 0, function* () {
if (accessToken === null) {
yield this.generateToken(false);
}
const filter = this.metricFilter("api/request_count");
const res = yield this.makeRequest(filter, startTime, endTime);
const cleanTimeSeries = yield this.cleanResponseTimeSeries(res);
return cleanTimeSeries;
});
}
}
exports.FirestoreMetrics = FirestoreMetrics;
//# sourceMappingURL=index.js.map