Skip to content

Commit

Permalink
SDK Health checks (#431)
Browse files Browse the repository at this point in the history
* initial commit

* errormessage recorded for all failures now

* restricted to request queue fails only

* added app_version

* warning and error recording with session update

* hc interface and comments

* test

* lint

* changelog

---------

Co-authored-by: Artūrs Kadiķis <kadikis.arturs@gmail.com>
  • Loading branch information
turtledreams and ArtursKadikis committed Jul 28, 2023
1 parent 46bc435 commit c626f92
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## X.X.X
- Added a new flag, 'loadAPMScriptsAsync', which can load the APM related scripts automatically for Async implementations
- Adding SDK health check requests after init
- Adding remaining request queue size information to every request
- Fixed a bug where unnecessary device ID merge information was sent to the server

Expand Down
37 changes: 37 additions & 0 deletions cypress/integration/health_check.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/* eslint-disable require-jsdoc */
var Countly = require("../../lib/countly");
var hp = require("../support/helper");

function initMain() {
Countly.init({
app_key: "YOUR_APP_KEY",
url: "https://try.count.ly",
test_mode: true
});
}

describe("Health Check tests ", () => {
it("Check if health check is sent at the beginning", () => {
hp.haltAndClearStorage(() => {
initMain();
cy.intercept("GET", "https://try.count.ly/i?**").as("getXhr");
cy.wait("@getXhr").then((xhr) => {
const url = new URL(xhr.request.url);

// Test the 'hc' parameter
const hcParam = url.searchParams.get("hc");
const hcParamObj = JSON.parse(hcParam);
expect(hcParamObj).to.eql({ el: 0, wl: 0, sc: -1, em: "\"\"" });

// Test the 'metrics' parameter
const metricsParam = url.searchParams.get("metrics");
expect(metricsParam).to.equal("{\"_app_version\":\"0.0\",\"_ua\":\"abcd\"}");

// check nothing in the request queue
cy.fetch_local_request_queue().then((rq) => {
expect(rq.length).to.equal(0);
});
});
});
});
});
122 changes: 121 additions & 1 deletion lib/countly.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,16 @@
BOOMERANG_SRC: "https://cdn.jsdelivr.net/npm/countly-sdk-web@latest/plugin/boomerang/boomerang.min.js",
CLY_BOOMERANG_SRC: "https://cdn.jsdelivr.net/npm/countly-sdk-web@latest/plugin/boomerang/countly_boomerang.js",
};

/**
* Health check counters' local storage keys
*/
var healthCheckCounterEnum = Object.freeze({
errorCount: "cly_hc_error_count",
warningCount: "cly_hc_warning_count",
statusCode: "cly_hc_status_code",
errorMessage: "cly_hc_error_message",
});
/**
* Async api queue, push commands here to be executed when script is loaded or after
* @example <caption>Add command as array</caption>
Expand Down Expand Up @@ -295,6 +305,10 @@
this.maxStackTraceLinesPerThread = getConfig("max_stack_trace_lines_per_thread", ob, configurationDefaultValues.MAX_STACKTRACE_LINES_PER_THREAD);
this.maxStackTraceLineLength = getConfig("max_stack_trace_line_length", ob, configurationDefaultValues.MAX_STACKTRACE_LINE_LENGTH);
this.heatmapWhitelist = getConfig("heatmap_whitelist", ob, []);
self.hcErrorCount = getValueFromStorage(healthCheckCounterEnum.errorCount) || 0;
self.hcWarningCount = getValueFromStorage(healthCheckCounterEnum.warningCount) || 0;
self.hcStatusCode = getValueFromStorage(healthCheckCounterEnum.statusCode) || -1;
self.hcErrorMessage = getValueFromStorage(healthCheckCounterEnum.errorMessage) || "";

if (maxCrashLogs && !this.maxBreadcrumbCount) {
this.maxBreadcrumbCount = maxCrashLogs;
Expand Down Expand Up @@ -3756,6 +3770,13 @@
if (last - lastBeat > sessionUpdate) {
self.session_duration(last - lastBeat);
lastBeat = last;
// save health check logging counters if there are any
if (self.hcErrorCount > 0) {
setValueInStorage(healthCheckCounterEnum.errorCount, self.hcErrorCount);
}
if (self.hcWarningCount > 0) {
setValueInStorage(healthCheckCounterEnum.warningCount, self.hcWarningCount);
}
}
}

Expand Down Expand Up @@ -3941,10 +3962,12 @@
if (level === logLevelEnums.ERROR) {
// eslint-disable-next-line no-console
console.error(log);
HealthCheck.incrementErrorCount();
}
else if (level === logLevelEnums.WARNING) {
// eslint-disable-next-line no-console
console.warn(log);
HealthCheck.incrementWarningCount();
}
else if (level === logLevelEnums.INFO) {
// eslint-disable-next-line no-console
Expand Down Expand Up @@ -4019,8 +4042,11 @@
}
else {
log(logLevelEnums.ERROR, functionName + " Failed Server XML HTTP request, ", this.status);
if (functionName === "send_request_queue") {
HealthCheck.saveRequestCounters(this.status, this.responseText);
}
if (typeof callback === "function") {
callback(true, params);
callback(true, params, this.status, this.responseText);
}
}
}
Expand Down Expand Up @@ -4491,7 +4517,101 @@
}
};

/**
* Health Check Interface:
* {sendInstantHCRequest} Sends instant health check request
* {resetAndSaveCounters} Resets and saves health check counters
* {incrementErrorCount} Increments health check error count
* {incrementWarningCount} Increments health check warning count
* {resetCounters} Resets health check counters
* {saveRequestCounters} Saves health check request counters
*/
var HealthCheck = {};
HealthCheck.sendInstantHCRequest = sendInstantHCRequest;
HealthCheck.resetAndSaveCounters = resetAndSaveCounters;
HealthCheck.incrementErrorCount = incrementErrorCount;
HealthCheck.incrementWarningCount = incrementWarningCount;
HealthCheck.resetCounters = resetCounters;
HealthCheck.saveRequestCounters = saveRequestCounters;
/**
* Increments health check error count
*/
function incrementErrorCount() {
self.hcErrorCount++;
}
/**
* Increments health check warning count
*/
function incrementWarningCount() {
self.hcWarningCount++;
}
/**
* Resets health check counters
*/
function resetCounters() {
self.hcErrorCount = 0;
self.hcWarningCount = 0;
self.hcStatusCode = -1;
self.hcErrorMessage = "";
}
/**
* Sets and saves the status code and error message counters
* @param {number} status - response status code of the request
* @param {string} responseText - response text of the request
*/
function saveRequestCounters(status, responseText) {
self.hcStatusCode = status;
self.hcErrorMessage = responseText;
setValueInStorage(healthCheckCounterEnum.statusCode, self.hcStatusCode);
setValueInStorage(healthCheckCounterEnum.errorMessage, self.hcErrorMessage);
}
/**
* Resets and saves health check counters
*/
function resetAndSaveCounters() {
HealthCheck.resetCounters();
setValueInStorage(healthCheckCounterEnum.errorCount, self.hcErrorCount);
setValueInStorage(healthCheckCounterEnum.warningCount, self.hcWarningCount);
setValueInStorage(healthCheckCounterEnum.statusCode, self.hcStatusCode);
setValueInStorage(healthCheckCounterEnum.errorMessage, self.hcErrorMessage);
}
/**
* Countly health check request sender
*/
function sendInstantHCRequest() {
// truncate error message to 1000 characters
var curbedMessage = truncateSingleValue(self.hcErrorMessage, 1000, "healthCheck", log);
// prepare hc object
var hc = {
el: self.hcErrorCount,
wl: self.hcWarningCount,
sc: self.hcStatusCode,
em: JSON.stringify(curbedMessage)
};
// prepare request
var request = {
hc: JSON.stringify(hc),
metrics: JSON.stringify({ _app_version: self.app_version })
};
// add common request params
prepareRequest(request);
// send request
sendXmlHttpRequest("healthCheck", self.url + apiPath, request, function(err, params, status, responseText) {
if (err) {
log(logLevelEnums.ERROR, "healthCheck, An error occurred. Status: [" + status + "], response: [" + responseText + "]");
}
else {
log(logLevelEnums.INFO, "healthCheck, Request was successful. Status: [" + status + "], response: [" + responseText + "]");
// reset and save health check counters if request was successful
HealthCheck.resetAndSaveCounters();
}
}, true);
}

// initialize Countly Class
this.initialize();
// send instant health check request
HealthCheck.sendInstantHCRequest();
};

/**
Expand Down

0 comments on commit c626f92

Please sign in to comment.