google-apps-script-better-logger
Version:
On google apps script use better logger. this package just a Better-Logger type assist.
419 lines (389 loc) • 12.3 kB
text/typescript
export const enum Levels {
EMERGENCY = 70, //緊急
ALERT = 60, //快訊
CRITICAL = 50, //重要
ERROR = 40, //錯誤
WARNING = 30, //警告
INFO = 20, //資訊
DEBUG = 10, //除錯
NOTICE = 0 //通知
}
export class BetterLogger {
description: string
sheet_id: string
sheet_page_name: string
logfmt: string
GMT: string
datefmt: string
level_label: string
level: number
user: string
Levels: Levels
levels: object
levels_colors: object
use_mail: boolean
levels_use_mail: object
mail_subject_fmt: string
application: string
use_sheet: boolean
use_console: boolean
sheet_log_slice: boolean
constructor() {
this.description =
"這是一個Logger,用法請看https://github.com/we684123/Google_Apps_Script_Logger"
this.sheet_id = ""
this.sheet_page_name = "Log"
this.logfmt =
"%{datefmt} - %{user} - %{levelname} : %{message}"
// 暫時只有這四個
this.GMT = "GMT+8"
this.datefmt = "yyyy.MM.dd HH:mm:ss z"
// 格式設定看這裡
// https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
this.levels = {
"EMERGENCY": Levels["EMERGENCY"],
"ALERT": Levels["ALERT"],
"CRITICAL": Levels["CRITICAL"],
"ERROR": Levels["ERROR"],
"WARNING": Levels["WARNING"],
"INFO": Levels["INFO"],
"DEBUG": Levels["DEBUG"],
"NOTICE": Levels["NOTICE"]
}
this.levels_colors = {
"EMERGENCY": "#ff0000",
"ALERT": "#980000",
"CRITICAL": "#e06666",
"ERROR": "#f6b26b",
"WARNING": "#ffe599",
"INFO": "#93c47d",
"DEBUG": "#76a5af",
"NOTICE": "#9fc5e8",
}
this.use_mail = false
this.levels_use_mail = {
"EMERGENCY": true,
"ALERT": true,
"CRITICAL": false,
"ERROR": false,
"WARNING": false,
"INFO": false,
"DEBUG": false,
"NOTICE": true,
}
this.mail_subject_fmt = "%{application} %{log_level}"
// 暫時就這2個
this.application = "Google_Apps_Script_Logger"
this.level_label = "WARNING"
this.level = this.get_level_correspond(this.level_label)
// ts-ignore
this.user = Session.getActiveUser().getEmail(); // todo
this.use_sheet = false
this.use_console = true
this.sheet_log_slice = true
}
public get_config(): string {
return `
description = ${this.description}
user = ${this.user}
GMT = ${this.GMT}
logfmt = ${this.logfmt}
datefmt = ${this.datefmt}
level = ${this.level}
level_label = ${this.level_label}
levels = ${JSON.stringify(this.levels)}
use_console = ${this.use_console}
use_sheet = ${this.use_sheet}
sheet_id = ${this.sheet_id}
sheet_page_name = ${this.sheet_page_name}
sheet_log_slice = ${this.sheet_log_slice}
levels_colors = ${JSON.stringify(this.levels_colors)}
use_mail = ${this.use_mail}
levels_use_mail = ${JSON.stringify(this.levels_use_mail)}
mail_subject_fmt = ${this.mail_subject_fmt}
application = ${this.application}
`
}
public set_config(
sheet_id: string,
sheet_page_name: string = "Log",
logfmt: string =
"%{datefmt} %{user} %{levelname} : %{message}",
GMT: string,
datefmt: string = "yyyy.MM.dd G 'at' HH:mm:ss z",
level: number = 30
): void {
this.sheet_id = sheet_id
this.sheet_page_name = sheet_page_name
this.logfmt = logfmt
this.GMT = GMT
this.datefmt = datefmt
this.level = level
this.level_label = "WARNING"
let rt = this.get_level_correspond(level, 0)
if (rt == undefined) {
throw (new Error("level is not allow!"))
}
this.level = rt
this.use_sheet = false
this.use_console = true
this.sheet_log_slice = true
}
public set_logfmt(logfmt: string): void {
this.logfmt = logfmt
}
public set_datefmt(datefmt: string): void {
this.datefmt = datefmt
}
public set_GMT(GMT: string): void {
this.GMT = GMT
}
public set_use_console(boolean: boolean) {
this.use_console = boolean
}
public set_use_sheet(boolean: boolean) {
this.use_sheet = boolean
}
public set_sheet_id(sheet_id: string): void {
this.sheet_id = sheet_id
}
public set_sheet_page_name(sheet_page_name: string): void {
this.sheet_page_name = sheet_page_name
}
public set_sheet_log_slice(boolean: boolean) {
this.sheet_log_slice = boolean
}
public set_level(level: string): void {
let rt = this.get_level_correspond(level, 0)
if (rt == undefined) {
throw (new Error("level is not allow!"))
}
this.level = rt
}
public set_EMERGENCY_color(color: string): void {
this.levels["EMERGENCY"] = color
}
public set_ALERT_color(color: string): void {
this.levels["ALERT"] = color
}
public set_CRITICAL_color(color: string): void {
this.levels["CRITICAL"] = color
}
public set_ERROR_color(color: string): void {
this.levels["ERROR"] = color
}
public set_WARNING_color(color: string): void {
this.levels["WARNING"] = color
}
public set_INFO_color(color: string): void {
this.levels["INFO"] = color
}
public set_DEBUG_color(color: string): void {
this.levels["DEBUG"] = color
}
public set_NOTICE_color(color: string): void {
this.levels["NOTICE"] = color
}
public set_use_mail(yn: boolean): void {
this.use_mail = yn
}
public set_EMERGENCY_mail(yn: boolean): void {
this.levels["EMERGENCY"] = yn
}
public set_ALERT_mail(yn: boolean): void {
this.levels["ALERT"] = yn
}
public set_CRITICAL_mail(yn: boolean): void {
this.levels["CRITICAL"] = yn
}
public set_ERROR_mail(yn: boolean): void {
this.levels["ERROR"] = yn
}
public set_WARNING_mail(yn: boolean): void {
this.levels["WARNING"] = yn
}
public set_INFO_mail(yn: boolean): void {
this.levels["INFO"] = yn
}
public set_DEBUG_mail(yn: boolean): void {
this.levels["DEBUG"] = yn
}
public set_NOTICE_mail(yn: boolean): void {
this.levels["NOTICE"] = yn
}
public log(level_label: Levels, text: string) {
this.do_log(level_label, text)
}
public emergency(text: string) {
this.do_log(Levels.EMERGENCY, text)
}
public alert(text: string) {
this.do_log(Levels.ALERT, text)
}
public critical(text: string) {
this.do_log(Levels.CRITICAL, text)
}
public error(text: string) {
this.do_log(Levels.ERROR, text)
}
public warning(text: string) {
this.do_log(Levels.WARNING, text)
}
public info(text: string) {
this.do_log(Levels.INFO, text)
}
public debug(text: string) {
this.do_log(Levels.DEBUG, text)
}
public notice(text: string) {
this.do_log(Levels.NOTICE, text)
}
public set_application(application: string) {
this.application = application
}
private ass_msg(levelname: string, message: string) {
let formattedDate = this.get_fmtdate()
return this.logfmt
.replace(/%{datefmt}/g, formattedDate)
.replace(/%{user}/g, this.user)
.replace(/%{levelname}/g, levelname)
.replace(/%{message}/g, message)
}
private ass_subject(level_label: string) {
return this.mail_subject_fmt
.replace(/%{application}/g, this.application)
.replace(/%{log_level}/g, level_label)
}
private get_fmtdate() {
// ts-ignore
return Utilities.formatDate(new Date(), this.GMT, this.datefmt) // todo
}
private get_level_correspond(level: any, type?: string | number) {
if (typeof (level) == typeof (type)) {
return level
}
// ES7 暫時封印
//const values_list = Object.values(this.levels)
const values_list = Object.keys(this.levels).map(key => this.levels[key]);
const keys_list = Object.keys(this.levels)
const correspond_ed = this.correspond(keys_list, values_list)
return correspond_ed[String(level)]
}
private correspond(keys_list: any[], values_list: any[]) {
if (keys_list.length != values_list.length) {
throw (new Error("keys_list and values_list length not equal."))
}
let correspond_aims = {}
for (let index = 0; index < keys_list.length; index++) {
correspond_aims[keys_list[index]] = values_list[index]
correspond_aims[values_list[index]] = keys_list[index]
}
return correspond_aims
}
private do_log(level: Levels, text: string) {
let level_label = this.get_level_correspond(level)
if (Number(level) >= Number(this.level)) {
if (this.use_console) {
const handle_level = (level: Levels, text: string): void => {
// console.log(Levels.CRITICAL, this.level, level_label)
switch (level) {
case Levels.EMERGENCY:
console.error(this.ass_msg(level_label, text));
break;
case Levels.ALERT:
console.error(this.ass_msg(level_label, text));
break;
case Levels.CRITICAL:
console.error(this.ass_msg(level_label, text));
break;
case Levels.ERROR:
console.error(this.ass_msg(level_label, text));
break;
case Levels.WARNING:
console.warn(this.ass_msg(level_label, text));
break;
case Levels.INFO:
console.info(this.ass_msg(level_label, text));
break;
case Levels.DEBUG:
console.info(this.ass_msg(level_label, text));
break;
case Levels.NOTICE:
console.info(this.ass_msg(level_label, text));
break;
default:
throw (new Error("No have this level!"));
}
}
handle_level(level, text)
}
if (this.use_sheet) {
let wt: string[]
if (this.sheet_log_slice) {
wt = []
let regexp = /%{([^\{\}]+)}/gi
let matches_array = this.logfmt.match(regexp);
for (let value of matches_array) {
if (value == "%{datefmt}") {
wt.push(this.get_fmtdate())
} else if (value == "%{user}") {
wt.push(this.user)
} else if (value == "%{levelname}") {
wt.push(level_label)
} else if (value == "%{message}") {
wt.push(text)
}
}
} else {
wt = [this.ass_msg(level_label, text)]
}
this.log_by_sheet(this.sheet_id, this.sheet_page_name, wt, level_label)
}
if (this.use_mail) {
if (this.levels_use_mail[level_label]) {
try {
// ts-ignore
GmailApp.sendEmail( // todo
this.user,
this.ass_subject(level_label),
this.ass_msg(level_label, text),
);
console.log(
`send a Email ,
${this.user},
${this.ass_subject(level_label)},
${this.ass_msg(level_label, text)}`
);
} catch (error) {
console.error(error);
}
}
}
}
}
private log_by_sheet( // todo
sheet_key: string,
page: string = "log",
text_array: string[] = [],
level_label: string
) {
// console.log(level_label);
// ts-ignore
const SpreadSheet = SpreadsheetApp.openById(sheet_key);
let sheet = SpreadSheet.getSheetByName(page);
if (sheet == null) {
sheet = SpreadSheet.insertSheet(page)
console.log(`creat a page (name = "${page}")`);
}
let SheetLastRow = sheet.getLastRow();
let LastRow_next = Number(SheetLastRow) + 1
let len_text_array = text_array.length
// console.log(this.levels_colors);
// console.log(`level_label = ${level_label}`);
let color = this.levels_colors[level_label]
sheet
.getRange(LastRow_next, 1, 1, len_text_array)
.setValues([text_array])
.setBackground(color)
}
}