diff --git a/server/src/config.ts b/server/src/config.ts index f11a843..e69a494 100644 --- a/server/src/config.ts +++ b/server/src/config.ts @@ -1,10 +1,11 @@ import { getJsonDataSync } from './services/json_service'; import { normalizeUrl } from './utils/url'; +import { parseTimeZone } from './utils/time'; import * as path from 'path'; import * as fs from 'fs'; import * as os from 'os'; - +import * as moment from 'moment'; let configFile = path.join(__dirname, '../../config.json'); let configExists = fs.existsSync(configFile); @@ -50,6 +51,7 @@ export const HASTIC_WEBHOOK_URL = getConfigField('HASTIC_WEBHOOK_URL', null); export const HASTIC_WEBHOOK_TYPE = getConfigField('HASTIC_WEBHOOK_TYPE', 'application/json'); export const HASTIC_WEBHOOK_SECRET = getConfigField('HASTIC_WEBHOOK_SECRET', null); export const HASTIC_WEBHOOK_IMAGE_ENABLED = getConfigField('HASTIC_WEBHOOK_IMAGE', false); +export const TIMEZONE_UTC_OFFSET = getTimeZoneOffset(); export const ANLYTICS_PING_INTERVAL = 500; // ms export const PACKAGE_VERSION = getPackageVersion(); @@ -145,3 +147,13 @@ function getDbConfig(connectionStr: string): DBConfig { }; return config; } + +function getTimeZoneOffset(): number { + let configTimeZone = getConfigField('TIMEZONE_UTC_OFFSET', null); + if(configTimeZone !== null) { + return parseTimeZone(configTimeZone); + } else { + const serverUtcOffset = moment().utcOffset(); + return serverUtcOffset; + } +} diff --git a/server/src/controllers/analytics_controller.ts b/server/src/controllers/analytics_controller.ts index 2eec633..5dbd7df 100644 --- a/server/src/controllers/analytics_controller.ts +++ b/server/src/controllers/analytics_controller.ts @@ -89,7 +89,7 @@ async function onPushDetect(detectionResult: DetectionResult): Promise { const segments = await onDetect(detectionResult); if(!_.isEmpty(segments) && analyticUnit.alert) { try { - const segment = await Segment.findOne(_.last(segments)) + const segment = await Segment.findOne(_.last(segments)); alertService.receiveAlert(analyticUnit, segment); } catch(err) { console.error(`error while sending webhook: ${err.message}`); diff --git a/server/src/services/alert_service.ts b/server/src/services/alert_service.ts index 7eef6c4..630cba1 100644 --- a/server/src/services/alert_service.ts +++ b/server/src/services/alert_service.ts @@ -2,6 +2,7 @@ import { sendNotification, MetaInfo, AnalyticMeta, WebhookType, Notification } f import * as AnalyticUnit from '../models/analytic_units'; import { Segment } from '../models/segment_model'; import { availableReporter } from '../utils/reporter'; +import { toTimeZone } from '../utils/time'; import { ORG_ID, HASTIC_API_KEY, HASTIC_WEBHOOK_IMAGE_ENABLED } from '../config'; import axios from 'axios'; @@ -77,12 +78,14 @@ export class Alert { } protected makeMessage(meta: AnalyticMeta): string { + const localTimeFrom = toTimeZone(meta.from); + const localTimeTo = toTimeZone(meta.to); return [ `[${meta.analyticUnitType.toUpperCase()} ALERTING] ${meta.analyticUnitName}`, `URL: ${meta.grafanaUrl}`, ``, - `From: ${new Date(meta.from)}`, - `To: ${new Date(meta.to)}`, + `From: ${localTimeFrom}`, + `To: ${localTimeTo}`, `ID: ${meta.analyticUnitId}`, `Message: ${meta.message}` ].join('\n'); @@ -103,12 +106,14 @@ class PatternAlert extends Alert { } protected makeMessage(meta: AnalyticMeta): string { + const localTimeFrom = toTimeZone(meta.from); + const localTimeTo = toTimeZone(meta.to); return [ `[PATTERN DETECTED] ${meta.analyticUnitName}`, `URL: ${meta.grafanaUrl}`, ``, - `From: ${new Date(meta.from)}`, - `To: ${new Date(meta.to)}`, + `From: ${localTimeFrom}`, + `To: ${localTimeTo}`, `ID: ${meta.analyticUnitId}` ].join('\n'); } @@ -141,11 +146,12 @@ class ThresholdAlert extends Alert { } protected makeMessage(meta: AnalyticMeta): string { + const localTimeFrom = toTimeZone(meta.from); let message = [ `[THRESHOLD ALERTING] ${meta.analyticUnitName}`, `URL: ${meta.grafanaUrl}`, ``, - `Starts at: ${new Date(meta.from)}`, + `Starts at: ${localTimeFrom}`, `ID: ${meta.analyticUnitId}` ].join('\n'); diff --git a/server/src/services/notification_service.ts b/server/src/services/notification_service.ts index 7fd369b..b101c46 100644 --- a/server/src/services/notification_service.ts +++ b/server/src/services/notification_service.ts @@ -1,5 +1,5 @@ import * as AnalyticUnit from '../models/analytic_units'; -import { HASTIC_WEBHOOK_URL, HASTIC_WEBHOOK_TYPE, HASTIC_WEBHOOK_SECRET, HASTIC_INSTANCE_NAME } from '../config'; +import { HASTIC_WEBHOOK_URL, HASTIC_WEBHOOK_TYPE, HASTIC_INSTANCE_NAME } from '../config'; import axios from 'axios'; import * as querystring from 'querystring'; diff --git a/server/src/utils/time.ts b/server/src/utils/time.ts new file mode 100644 index 0000000..c0d67b0 --- /dev/null +++ b/server/src/utils/time.ts @@ -0,0 +1,26 @@ +import { TIMEZONE_UTC_OFFSET } from '../config'; + +import * as _ from 'lodash'; +import * as moment from 'moment'; + +const MINUTES_IN_HOUR = 60; + +export function parseTimeZone(timeZone: string): number { + const re = /\b-?\d{1,2}?:\d{2}\b/; + const correctFormat = re.test(timeZone); + if(!correctFormat) { + throw new Error(`Wrong timeZone format in config - "TIMEZONE_UTC_OFFSET": ${timeZone}`); + } + const time = _.split(timeZone, ':'); + let minutesOffset = Math.abs(Number(time[0])) * MINUTES_IN_HOUR + Number(time[1]); + if(timeZone.indexOf('-') !== -1) { + minutesOffset = -1 * minutesOffset; + } + return minutesOffset; +} + +export function toTimeZone(time: moment.MomentInput): string { + const utcTime = moment(time).utc(); + const timeWithOffset = utcTime.utcOffset(TIMEZONE_UTC_OFFSET); + return timeWithOffset.format('ddd MMM DD YYYY HH:mm:ss'); +}