Created
April 23, 2021 14:28
-
-
Save Max-Makhrov/6b7d407414950dd499a41ad75c0b6886 to your computer and use it in GitHub Desktop.
Timer is a code for monitoring onMinute triggers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function readTimer() { | |
// [ 1 ]. Get report | |
var tags = ['onMinute_admin', 'onMinute_worker', 'onMinute_importer', 'onMinute_sizif1', 'onMinute_sizif2']; | |
var report = getTimerReps_(tags); | |
console.log(report); | |
// => gives 2D Array with a report about executions. | |
// So U can write it on Spreadsheet. | |
// [ 2 ]. Gat all data from logs | |
// var timer = Timer_('onMinute_admin'); | |
// var data = timer.get(); | |
// | |
// | |
// returns JSON | |
// like: | |
// | |
/************* | |
data = | |
{ | |
log: | |
{"2021-04-21": | |
{ firstTime: "2021-04-18T18:24:12.106Z", | |
lastTime: "2021-04-21T05:42:11.998Z", | |
totatTime: 9147497, | |
starts: 252 | |
ends: 250 | |
executions: | |
{"1618793652120": | |
{ | |
"start": "2021-04-21T11:17:12.250Z", | |
"end": "2021-04-21T11:17:12.412Z", | |
"time": 162, | |
"startNote": "ok", | |
"endNote": "Done! => " | |
} | |
} | |
} | |
} | |
days: ['2021-04-21', '2021-04-20', '2021-04-21'] | |
} | |
************/ | |
// notes | |
// log = the main object with totals: | |
// firstTime = the time of first execution | |
// lastTime = the time of last execution | |
// totatTime = total time of execution, ms | |
// starts = number of started execution | |
// ends = number of ended executions | |
// executions = object with each execution | |
// days = the array of days in log | |
/*********** | |
console.log(Object.keys(data)); // [log, days] | |
************/ | |
} | |
// _ _ _ | |
// | | | | | | | |
// | |__| | ___| |_ __ ___ _ __ ___ | |
// | __ |/ _ \ | '_ \ / _ \ '__/ __| | |
// | | | | __/ | |_) | __/ | \__ \ | |
// |_| |_|\___|_| .__/ \___|_| |___/ | |
// | | | |
// |_| | |
// function test_getFormattedDay() { | |
// // 2021-04-22 | |
// console.log(getFormattedDay_(new Date())); | |
// } | |
function getFormattedDay_(date, format) { | |
date = date || new Date(); | |
format = format || 'yyy-MM-dd'; | |
var d = new Date(date); | |
var timezone = Session.getScriptTimeZone(); | |
return Utilities.formatDate(d,timezone, 'yyy-MM-dd'); | |
} | |
// | |
// function test_millisec2humantime() { | |
// // 2 min. 3 sec. | |
// console.log(millisec2humantime_(123456)); | |
// } | |
function millisec2humantime_(milli) { | |
if (milli < 1000) { return milli + ' ms.'; } | |
var mm = parseInt(milli/1000), respo = ''; | |
if (mm < 60) { | |
respo = mm + ' sec.'; | |
} else { | |
var min = parseInt(mm / 60); | |
var sec = mm - min *60; | |
respo = min + ' min. ' + sec + ' sec.'; | |
} | |
return respo; | |
} | |
// _______ _ | |
// |__ __(_) | |
// | | _ _ __ ___ ___ _ __ | |
// | | | | '_ ` _ \ / _ \ '__| | |
// | | | | | | | | | __/ | | |
// |_| |_|_| |_| |_|\___|_| | |
// | |
// function testTimer() { | |
// var timer = Timer_('BoooDaaaYaaaBooo'); | |
// // | |
// // 1 | |
// var executionId = timer.start('started'); | |
// // console.log(executionId); | |
// // Do smth useful | |
// Utilities.sleep(500); | |
// var endRes = timer.end(executionId, 'Done!') | |
// // | |
// // 2 | |
// var executionId = timer.start('started again'); | |
// // Do smth ueful | |
// Utilities.sleep(1500); | |
// var endRes = timer.end(executionId, 'Done again!'); | |
// console.log(JSON.stringify(timer.get(), null,4)); | |
// // | |
// timer.remove(); | |
// } | |
function Timer_(logKey) { | |
// [ 1 ]. constants | |
// number of days to keep in memory | |
var daysToKeep = 3; | |
// seconds of memory life | |
// is seconds | |
// ~ 1 hour + 6 minutes | |
var cacheLife = 4000; | |
var self = this; | |
self.logKey = logKey; | |
// | |
// [ 2 ]. work with memory | |
var cache = CacheService.getScriptCache(); | |
var chunky = ChunkyCache_(cache); | |
self.mem = { | |
days: [], | |
log: {} // day { ...info... } | |
} | |
self.getMemory_ = function() { | |
var mem = {}; | |
var s_mem = chunky.get(self.logKey); | |
if (s_mem) { mem = JSON.parse(s_mem); } else { | |
mem = self.mem; | |
} | |
return mem; | |
} | |
self.setMemory_ = function(mem) { | |
var s_mem = JSON.stringify(mem); | |
chunky.put(self.logKey, s_mem, cacheLife); | |
} | |
self.remove_ = function() { | |
chunky.remove(self.logKey); | |
} | |
// | |
// | |
// [ 4 ]. Execute memory tasks | |
return { | |
// function to start writing time | |
start: function(note) { | |
try { | |
// get current object | |
var d = new Date(); | |
var executionId = d.getTime(); | |
// get the day of start | |
var day = getFormattedDay_(d); | |
// get memory object | |
var mem = self.getMemory_(); | |
// get days of memory | |
var days = []; | |
days = mem.days || days; | |
// add current day to memory | |
if (days.indexOf(day) === -1) { | |
days.push(day); // add day | |
} | |
// delete extra days from cache | |
if (days.length > daysToKeep) { | |
// deletes 1 day at a time | |
var removedDay = days.shift(); | |
delete mem.log[removedDay]; | |
} | |
// add day to memory | |
mem.days = days; | |
var dayLog = mem.log[day]; | |
var execution = {start: d, end: null, time: 0, startNote: note} | |
if (!dayLog) { | |
// add new day log | |
dayLog = { | |
starts: 1, | |
ends: 0, | |
totatTime: 0, | |
firstTime: d, | |
lastTime: d, | |
executions: {} | |
} | |
dayLog.executions[executionId] = execution; | |
} else { | |
// add new data to log | |
dayLog.starts++; | |
dayLog.lastTime = d; | |
dayLog.executions[executionId] = execution; | |
} | |
mem.log[day] = dayLog; | |
self.setMemory_(mem); | |
return executionId; | |
} catch(err) { | |
console.log('🤷♂️ timer mem start = ' + err); | |
return null; | |
} | |
}, | |
// function to end writing time to memory | |
end: function(executionId, note) { | |
try { | |
if (!executionId) { return -500; } | |
// get current object | |
var d = new Date(); | |
// get memory object | |
var mem = self.getMemory_(); | |
// get the day of start from memory | |
var days = []; | |
days = mem.days || days; | |
var l = days.length; | |
if (l === 0) { return -1; } | |
var day = days[l - 1]; | |
var dayLog = mem.log[day]; | |
if (!dayLog) { return -2; } | |
var executions = dayLog.executions; | |
if (!executions) { return -3; } | |
var execution = executions[executionId]; | |
if (!execution) { return -4; } | |
if (execution.end) { return -5; } // ended... | |
// write the result | |
execution.end = d; | |
var time = d - new Date(execution.start) | |
// execution | |
execution.time = time; | |
execution.endNote = note; | |
executions[executionId] = execution; | |
// day log | |
dayLog.executions = executions; | |
dayLog.totatTime += time; | |
dayLog.ends++; | |
mem.log[day] = dayLog; | |
self.setMemory_(mem); | |
return mem; | |
} catch(err) { | |
console.log('🤷♂️ timer mem end ' + err); | |
} | |
}, | |
get: function() { | |
var mem = self.getMemory_(); | |
return mem; | |
}, | |
remove: function() { | |
self.remove_(); | |
} | |
}; | |
} | |
// | |
// | |
// | |
// Timer Reports -- separate function to get timer reports by tag | |
function getTimerReps_(tags) { | |
var out = []; | |
var header = [ | |
'Tag', | |
'Day', | |
'Hour', | |
'Stat Note', | |
'End Note', | |
'Executions Started', | |
'Executions Ended', | |
'Time, ms' | |
]; | |
out.push(header); | |
// | |
for (var i = 0; i < tags.length; i++) { | |
out = out.concat(getTimerRep_(tags[i])); | |
} | |
return out; | |
} | |
// | |
function getTimerRep_(tag) { | |
var timer = Timer_(tag); | |
var data = timer.get(); | |
var days = data.days; | |
var out = []; | |
var row = [], key = '', groups = {}, group = {}, executions = {}, execution = {}, hour, dd; | |
// key inside Day: | |
// Hour + Start Note + End Note | |
for (var i = 0; i < days.length; i++) { | |
groups = {}; // new groups for new day | |
executions = data.log[days[i]].executions; | |
for (var ekey in executions) { | |
execution = executions[ekey]; | |
// { | |
// "start": "2021-04-20T16:01:12.111Z", | |
// "end": "2021-04-20T16:01:19.725Z", | |
// "time": 7614, | |
// "startNote": "ok", | |
// "endNote": "Done! => updateConnections_ClientNewDB" | |
// } | |
dd = new Date(execution.start); | |
hour = dd.getHours() + 1 | |
key = hour + execution.startNote + execution.endNote; | |
if (!groups[key]) { | |
group = { | |
hour: hour, | |
startNote: execution.startNote, | |
endNote: execution.endNote, | |
starts: 1, | |
ends: 0, | |
time: 0 | |
}; | |
} else { | |
group = groups[key]; | |
group.starts++; | |
} | |
if (execution.end) { | |
group.ends++; | |
group.time += execution.time; | |
} | |
groups[key] = group; | |
} | |
for (var gkey in groups) { | |
group = groups[gkey]; | |
row = [ | |
tag, | |
days[i], | |
group.hour, | |
group.startNote, | |
group.endNote, | |
group.starts, | |
group.ends, | |
group.time | |
]; | |
out.push(row); | |
} | |
} | |
return out; | |
} | |
// _____ _ | |
// / ____| | | | |
// | | __ _ ___| |__ ___ | |
// | | / _` |/ __| '_ \ / _ \ | |
// | |___| (_| | (__| | | | __/ | |
// \_____\__,_|\___|_| |_|\___| | |
// | |
// | |
// the code is from here: https://gist.github.com/pilbot/9d0567ef1daf556449fb | |
// function testGetCacheFrom() { | |
// var cache = CacheService.getScriptCache(); | |
// var chunky = ChunkyCache_(cache); | |
// var s = '🧞♂️'.repeat(1024 * 400); | |
// chunky.put('Data', s, 120); | |
// var check = chunky.get('Data'); | |
// // console.log(check); | |
// //console.log(Utilities.newBlob(s).getBytes().length); // length in KB | |
// } | |
function ChunkyCache_(cache){ | |
return { | |
// ttl = expirationInSeconds | |
// The minimum is 1 second and the maximum is 21600 seconds (6 hours). | |
// https://developers.google.com/apps-script/reference/cache/cache#putkey,-value,-expirationinseconds | |
put: function (key, value, ttl) { | |
var json = JSON.stringify(value); | |
// 1024*90 = indicates 90KB of data; should be ok with quota | |
var chunkSize = 1024*90; // put chunk size here | |
// this gives chunk size max 45KB | |
// a half of limit, discussion: | |
// https://gist.github.com/pilbot/9d0567ef1daf556449fb | |
var cSize = Math.floor(chunkSize / 2); | |
var chunks = []; | |
var index = 0; | |
while (index < json.length){ | |
cKey = key + "_" + index; | |
chunks.push(cKey); | |
// https://developers.google.com/apps-script/reference/cache/cache#putkey,-value,-expirationinseconds | |
// The cap for cached items is 1,000 | |
// If more than 1,000 items are written, the cache stores the 900 items farthest from expiration. | |
var part = json.substr(index, cSize); | |
// console.log(Utilities.newBlob(part).getBytes().length / 1024); // get length in Kb | |
cache.put(cKey, part, ttl+5); | |
index += cSize; | |
} | |
var superBlk = { | |
chunkSize: chunkSize, | |
chunks: chunks, | |
length: json.length | |
}; | |
cache.put(key, JSON.stringify(superBlk), ttl); | |
}, | |
get: function (key) { | |
var superBlkCache = cache.get(key); | |
if (superBlkCache != null) { | |
var superBlk = JSON.parse(superBlkCache); | |
if (!superBlk.chunks) { return null; } | |
chunks = superBlk.chunks.map(function (cKey){ | |
return cache.get(cKey); | |
}); | |
if (chunks.every(function (c) { return c != null; })){ | |
return JSON.parse(chunks.join('')); | |
} | |
} | |
}, | |
remove: function(key) { | |
var superBlkCache = cache.get(key); | |
if (superBlkCache != null) { | |
var superBlk = JSON.parse(superBlkCache); | |
superBlk.chunks.forEach(function (cKey){ | |
cache.remove(cKey); | |
}); | |
} | |
} | |
} | |
}; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment