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
@@ -1,6 +1,7 @@
## Version 25.03.X
Fixes:
- [core] Fixed duplicate conditional in form field template
- [alerts] Fixed alert jobs using system's timezone instead of application's

Enterprise Fixes:
- [data-manager] Fix notification message after editing user property
Expand Down
24 changes: 5 additions & 19 deletions plugins/alerts/api/alertModules/cohorts.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,24 @@ const log = require('../../../../api/utils/log.js')('alert:cohorts');
const moment = require('moment-timezone');
const common = require('../../../../api/utils/common.js');
const commonLib = require("../parts/common-lib.js");
const { ObjectId } = require('mongodb');

module.exports.check = async function({ alertConfigs: alert, done, scheduledTo: date }) {
const app = await common.readBatcher.getOne("apps", { _id: new ObjectId(alert.selectedApps[0]) });
if (!app) {
log.e(`App ${alert.selectedApps[0]} couldn't be found`);
return done();
}

module.exports.check = async function({ alert, app, done, scheduledTo: date }) {
let { period, alertDataSubType2, compareType, compareValue } = alert;
compareValue = Number(compareValue);

const metricValue = await getCohortMetricByDate(app, alertDataSubType2, date, period) || 0;
log.d(alert._id, "value on", date, "is", metricValue);

if (compareType === commonLib.COMPARE_TYPE_ENUM.MORE_THAN) {
if (metricValue > compareValue) {
log.d(alert._id, "triggered because", metricValue, "is more than", compareValue);
await commonLib.trigger({ alert, app, metricValue, date }, log);
}
}
else {
const before = moment(date).subtract(1, commonLib.PERIOD_TO_DATE_COMPONENT_MAP[period]).toDate();
const metricValueBefore = await getCohortMetricByDate(app, alertDataSubType2, before, period);
log.d(alert._id, "value on", before, "is", metricValueBefore);
if (!metricValueBefore) {
return done();
}
Expand All @@ -38,6 +34,7 @@ module.exports.check = async function({ alertConfigs: alert, done, scheduledTo:
: change <= -compareValue;

if (shouldTrigger) {
log.d(alert._id, "triggered because", compareType, String(change) + "%");
await commonLib.trigger({ alert, app, date, metricValue, metricValueBefore }, log);
}
}
Expand Down Expand Up @@ -83,14 +80,3 @@ async function getCohortMetricByDate(app, cohortId, date, period) {
}
}

/*
(async function() {
await new Promise(res => setTimeout(res, 2000));
const app = { _id: ObjectId("65c1f875a12e98a328d5eb9e"), timezone: "Europe/Istanbul" };
const date = new Date("2024-02-07T12:00:00.000Z");
const cohort = "3bcc37740d564419586ec26b66ea7c32";
let monthlyData = await getCohortMetricByDate(app, cohort, date, "monthly");
let dailyData = await getCohortMetricByDate(app, cohort, date, "daily");
console.log(monthlyData, dailyData);
})();
*/
27 changes: 6 additions & 21 deletions plugins/alerts/api/alertModules/crashes.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ const log = require('../../../../api/utils/log.js')('alert:crashes');
const moment = require('moment-timezone');
const common = require('../../../../api/utils/common.js');
const commonLib = require("../parts/common-lib.js");
const { ObjectId } = require('mongodb');

const METRIC_TO_PROPERTY_MAP = {
"non-fatal crashes/errors per session": "crnfses",
Expand Down Expand Up @@ -49,26 +48,23 @@ async function triggerByEvent(payload) {
}


module.exports.check = async function({ alertConfigs: alert, done, scheduledTo: date }) {
const app = await common.readBatcher.getOne("apps", { _id: new ObjectId(alert.selectedApps[0]) });
if (!app) {
log.e(`App ${alert.selectedApps[0]} couldn't be found`);
return done();
}

module.exports.check = async function({ alert, app, done, scheduledTo: date }) {
let { alertDataSubType, period, compareType, compareValue, filterValue } = alert;
compareValue = Number(compareValue);

const metricValue = await calculateMetricByDate(app, alertDataSubType, date, period, filterValue) || 0;
log.d(alert._id, "value on", date, "is", metricValue);

if (compareType === commonLib.COMPARE_TYPE_ENUM.MORE_THAN) {
if (metricValue > compareValue) {
log.d(alert._id, "triggered because", metricValue, "is more than", compareValue);
await commonLib.trigger({ alert, app, metricValue, date }, log);
}
}
else {
const before = moment(date).subtract(1, commonLib.PERIOD_TO_DATE_COMPONENT_MAP[period]).toDate();
const metricValueBefore = await calculateMetricByDate(app, alertDataSubType, before, period, filterValue);
log.d(alert._id, "value on", before, "is", metricValueBefore);
if (!metricValueBefore) {
return done();
}
Expand All @@ -79,6 +75,7 @@ module.exports.check = async function({ alertConfigs: alert, done, scheduledTo:
: change <= -compareValue;

if (shouldTrigger) {
log.d(alert._id, "triggered because", compareType, String(change) + "%");
await commonLib.trigger({ alert, app, date, metricValue, metricValueBefore }, log);
}
}
Expand All @@ -87,7 +84,7 @@ module.exports.check = async function({ alertConfigs: alert, done, scheduledTo:
};

/**
* Abstraction on top of getCrashDataByDate to calculate composite metrics.
* Abstraction on top of getCrashDataByDate to calculate composite metrics.
* Possible metricStrings:
* - non-fatal crashes/errors per session
* - fatal crashes/errors per session
Expand Down Expand Up @@ -174,15 +171,3 @@ async function getCrashDataByDate(app, metric, date, period, versions) {
}
return number;
}

/*
(async function() {
await new Promise(res => setTimeout(res, 2000));
const app = { _id: ObjectId("65c1f875a12e98a328d5eb9e"), timezone: "Europe/Istanbul" };
const date = new Date("2024-02-07T12:00:00.000Z");
let monthlyData = await getCrashDataByDate(app, "cr_u", date, "monthly");
let dailyData = await getCrashDataByDate(app, "cr_u", date, "daily", ["4:02:0", "4:01:2"]);
console.log(monthlyData, dailyData);
console.log(await calculateMetricByDate(app, "# of crashes/errors", date, "daily"));
})();
*/
76 changes: 24 additions & 52 deletions plugins/alerts/api/alertModules/dataPoints.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,54 +6,40 @@ const log = require('../../../../api/utils/log.js')('alert:dataPoints');
const moment = require('moment-timezone');
const common = require('../../../../api/utils/common.js');
const commonLib = require("../parts/common-lib.js");
const { ObjectId } = require('mongodb');

const DATA_POINT_PROPERTY = "dp";

module.exports.check = async function({ alertConfigs: alert, done, scheduledTo: date }) {
const selectedApp = alert.selectedApps[0];
let apps;
if (selectedApp === "all") {
apps = await common.readBatcher.getMany("apps", {});
}
else {
apps = [await common.readBatcher.getOne("apps", { _id: new ObjectId(selectedApp) })];
}
module.exports.check = async function({ alert, app, done, scheduledTo: date }) {
let { period, compareType, compareValue } = alert;
compareValue = Number(compareValue);

for (let app of apps) {
if (!app) {
log.e(`App ${alert.selectedApps[0]} couldn't be found`);
continue;
}
const metricValue = await getDataPointByDate(app, date, period) || 0;
log.d(alert._id, "value on", date, "is", metricValue);

let { period, compareType, compareValue } = alert;
compareValue = Number(compareValue);

const metricValue = await getDataPointByDate(app, date, period) || 0;

if (compareType === commonLib.COMPARE_TYPE_ENUM.MORE_THAN) {
if (metricValue > compareValue) {
await commonLib.trigger({ alert, app, metricValue, date }, log);
}
if (compareType === commonLib.COMPARE_TYPE_ENUM.MORE_THAN) {
if (metricValue > compareValue) {
log.d(alert._id, "triggered because", metricValue, "is more than", compareValue);
await commonLib.trigger({ alert, app, metricValue, date }, log);
}
}
else {
const before = moment(date).subtract(1, commonLib.PERIOD_TO_DATE_COMPONENT_MAP[period]).toDate();
const metricValueBefore = await getDataPointByDate(app, before, period);
log.d(alert._id, "value on", before, "is", metricValueBefore);
if (!metricValueBefore) {
return done();
}
else {
const before = moment(date).subtract(1, commonLib.PERIOD_TO_DATE_COMPONENT_MAP[period]).toDate();
const metricValueBefore = await getDataPointByDate(app, before, period);
if (!metricValueBefore) {
continue;
}

const change = (metricValue / metricValueBefore - 1) * 100;
const shouldTrigger = compareType === commonLib.COMPARE_TYPE_ENUM.INCREASED_BY
? change >= compareValue
: change <= -compareValue;
const change = (metricValue / metricValueBefore - 1) * 100;
const shouldTrigger = compareType === commonLib.COMPARE_TYPE_ENUM.INCREASED_BY
? change >= compareValue
: change <= -compareValue;

if (shouldTrigger) {
await commonLib.trigger({ alert, app, date, metricValue, metricValueBefore }, log);
}
if (shouldTrigger) {
log.d(alert._id, "triggered because", compareType, String(change) + "%");
await commonLib.trigger({ alert, app, date, metricValue, metricValueBefore }, log);
}
}

done();
};

Expand Down Expand Up @@ -117,17 +103,3 @@ function dailySum(dailyData) {
}
return dailyValue;
}
/*
(async function() {
await new Promise(res => setTimeout(res, 2000));
const app = { _id: ObjectId("65c1f875a12e98a328d5eb9e"), timezone: "Europe/Istanbul" };
const date1 = new Date("2024-01-07T10:00:00.000Z");
const date2 = new Date("2024-02-07T10:00:00.000Z");
const date3 = new Date("2024-03-07T10:00:00.000Z");
let monthlyData1 = await getDataPointByDate(app, date1, "monthly");
let monthlyData2 = await getDataPointByDate(app, date2, "monthly");
let monthlyData3 = await getDataPointByDate(app, date3, "monthly");
console.log("monthly:", monthlyData1, monthlyData2, monthlyData3);
console.log("all:", monthlyData1 + monthlyData2 + monthlyData3);
})();
*/
37 changes: 5 additions & 32 deletions plugins/alerts/api/alertModules/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ const log = require('../../../../api/utils/log.js')('alert:events');
const moment = require('moment-timezone');
const common = require('../../../../api/utils/common.js');
const commonLib = require("../parts/common-lib.js");
const { ObjectId } = require('mongodb');

const METRIC_TO_PROPERTY_MAP = {
// these are directly being stored in db
Expand All @@ -20,13 +19,7 @@ const METRIC_TO_PROPERTY_MAP = {

const AVERAGE_METRICS = ["average sum", "average duration"];

module.exports.check = async({ alertConfigs: alert, done, scheduledTo: date }) => {
const app = await common.readBatcher.getOne("apps", { _id: new ObjectId(alert.selectedApps[0]) });
if (!app) {
log.e(`App ${alert.selectedApps[0]} couldn't be found`);
return done();
}

module.exports.check = async({ alert, app, done, scheduledTo: date }) => {
let { alertDataSubType, alertDataSubType2, period, compareType, compareValue, filterKey, filterValue } = alert;
const metricProp = METRIC_TO_PROPERTY_MAP[alertDataSubType];
let segments;
Expand All @@ -45,9 +38,11 @@ module.exports.check = async({ alertConfigs: alert, done, scheduledTo: date }) =
}
metricValue /= count;
}
log.d(alert._id, "value on", date, "is", metricValue);

if (compareType === commonLib.COMPARE_TYPE_ENUM.MORE_THAN) {
if (metricValue > compareValue) {
log.d(alert._id, "triggered because", metricValue, "is more than", compareValue);
await commonLib.trigger({ alert, app, metricValue, date }, log);
}
}
Expand All @@ -67,13 +62,15 @@ module.exports.check = async({ alertConfigs: alert, done, scheduledTo: date }) =
}
metricValueBefore /= count;
}
log.d(alert._id, "value on", before, "is", metricValueBefore);

const change = (metricValue / metricValueBefore - 1) * 100;
const shouldTrigger = compareType === commonLib.COMPARE_TYPE_ENUM.INCREASED_BY
? change >= compareValue
: change <= -compareValue;

if (shouldTrigger) {
log.d(alert._id, "triggered because", compareType, String(change) + "%");
await commonLib.trigger({ alert, app, date, metricValue, metricValueBefore }, log);
}
}
Expand Down Expand Up @@ -155,27 +152,3 @@ async function getEventMetricByDate(app, event, metric, date, period, segments)
}
return number;
}
/*
(async function() {
if (!require("cluster").isPrimary) {
return;
}
await new Promise(res => setTimeout(res, 2000));
const app = { _id: "67fff00d901abe2f8cc57646", timezone: "Europe/Istanbul" };
const date = new Date("2025-02-02T12:47:19.247Z");
const event = "Product Viewed";
const prop = "c";

const hourly = await getEventMetricByDate(app, event, prop, date, "hourly");
console.assert(hourly === 5, "hourly event data doesn't match");

const daily = await getEventMetricByDate(app, event, prop, date2, "daily", { "Delivery Type": "Express" });
console.assert(daily === 22, "daily segmented event data doesn't match");

const monthly = await getEventMetricByDate(app, event, prop, date2, "monthly");
console.assert(monthly === 5120, "monthly event data doesn't match");

const monthlySegmented = await getEventMetricByDate(app, event, prop, date2, "monthly", { "Delivery Type": "Express" });
console.assert(monthlySegmented === 2535, "monthly segmented event data doesn't match");
})();
*/
29 changes: 5 additions & 24 deletions plugins/alerts/api/alertModules/nps.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ const log = require('../../../../api/utils/log.js')('alert:nps');
const moment = require('moment-timezone');
const common = require('../../../../api/utils/common.js');
const commonLib = require("../parts/common-lib.js");
const { ObjectId } = require('mongodb');

module.exports.triggerByEvent = triggerByEvent;
/**
Expand Down Expand Up @@ -50,26 +49,23 @@ async function triggerByEvent(payload) {
}
}

module.exports.check = async function({ alertConfigs: alert, done, scheduledTo: date }) {
const app = await common.readBatcher.getOne("apps", { _id: new ObjectId(alert.selectedApps[0]) });
if (!app) {
log.e(`App ${alert.selectedApps[0]} couldn't be found`);
return done();
}

module.exports.check = async function({ alert, app, done, scheduledTo: date }) {
let { period, alertDataSubType2, compareType, compareValue, filterValue } = alert;
compareValue = Number(compareValue);

const metricValue = await getResponsesByDate(app, alertDataSubType2, date, period, filterValue) || 0;
log.d(alert._id, "value on", date, "is", metricValue);

if (compareType === commonLib.COMPARE_TYPE_ENUM.MORE_THAN) {
if (metricValue > compareValue) {
log.d(alert._id, "triggered because", metricValue, "is more than", compareValue);
await commonLib.trigger({ alert, app, metricValue, date }, log);
}
}
else {
const before = moment(date).subtract(1, commonLib.PERIOD_TO_DATE_COMPONENT_MAP[period]).toDate();
const metricValueBefore = await getResponsesByDate(app, alertDataSubType2, before, period, filterValue);
log.d(alert._id, "value on", before, "is", metricValueBefore);
if (!metricValueBefore) {
return done();
}
Expand All @@ -80,6 +76,7 @@ module.exports.check = async function({ alertConfigs: alert, done, scheduledTo:
: change <= -compareValue;

if (shouldTrigger) {
log.d(alert._id, "triggered because", compareType, String(change) + "%");
await commonLib.trigger({ alert, app, date, metricValue, metricValueBefore }, log);
}
}
Expand Down Expand Up @@ -164,19 +161,3 @@ function sumOfAllResponses(scope, nps, score) {
return numberOfResponses;
}

/*
(async function() {
const app = {name: "test", _id: new ObjectId("6600901a71159e99a3434253"), timezone: "Europe/Istanbul", plugins: null };
const nps = "6600909ed476e1837317dc52";
const date = new Date("2024-09-16T12:00:00.000Z");

let data = await getResponsesByDate(app, nps, date, "monthly");
console.log("monthly:", data);

data = await getResponsesByDate(app, nps, date, "daily");
console.log("daily:", data);

data = await getResponsesByDate(app, nps, date, "hourly");
console.log("hourly:", data);
})();
*/
Loading
Loading