初めに
数年ぶりに記事投稿
最近、社内SEに転職し、ゆる~くServiceNowを触っております。
ServiceNowではコンテキスト系のログ出力があまり充実していないみたいなので出来るだけ簡単にそういった情報も出せるようなロガークラスをChatgptにも聞きながら考えたいと思います。
PDI環境
試したPDI環境はこんな感じです。
Version: Zurich

Studioからアプリケーションを作成
Scopeはどっちでもいいですが、全アプリ共通に使うならGlobalでもいいかもしれないです。

アプリが作成されたら、Create FileでScriptIncludeを作成します。

シンプルなLogger作成
ひとまず、適当なNameをつけ、Accessible fromはAll Application scopesにしておきます。

まずはシンプルなロガーとしてこんな感じの作ってみました。
// ************************************************************
// Constant Variables
// ************************************************************
const Constants = Class.create();
Constants.DEFAULT_PREFIX = "MY_COMMON_LOGGER";
Constants.LOG_LEVEL_INFO = "INFO";
Constants.LOG_LEVEL_WARN = "WARN";
Constants.LOG_LEVEL_ERROR = "ERROR";
Constants.LOG_LEVEL_DEBUG = "DEBUG";
var CommonMyLogger = Class.create();
CommonMyLogger.prototype = {
/**
* オブジェクト生成時に呼ばれるクラス(コンストラクタ).
* @function initialize
* @param {Array} prefix - prefix log.
* @returns {None} return no values.
*/
initialize: function(prefix) {
// 任意のプレフィックス
this._prefix = prefix ?? Constants.DEFAULT_PREFIX;
},
// ************************************************************
// Private Functions
// ************************************************************
/**
* ログ出力を整形する為の関数
* @function _formatMsg
* @param {string} level - Log level.
* @param {string} mgs - log message.
* @returns {string} formatted log message.
*/
_formatMsg: function(level, msg) {
return "PREFIX = " + this._prefix + " [" + level + "] " + msg;
},
// ************************************************************
// Public Functions
// ************************************************************
info: function(msg) {
gs.info(this._formatMsg(Constants.LOG_LEVEL_INFO, msg));
},
warn: function(msg) {
gs.warn(this._formatMsg(Constants.LOG_LEVEL_WARN, msg));
},
error: function(msg) {
gs.error(this._formatMsg(Constants.LOG_LEVEL_ERROR, msg));
},
debug: function(msg) {
gs.debug(this._formatMsg(Constants.LOG_LEVEL_DEBUG, msg));
},
type: 'CommonMyLogger'
};
呼び出し用のテーブルとUIアクションやビジネスルールを作成します。
※テーブルは適当にTaskでも継承しておきます。
UIアクションからはこのように呼び出して確認します。
const log = new x_1603370_logtes_0.CommonMyLogger();
log.info("ログのテストをしています...");
const log2 = new x_1603370_logtes_0.CommonMyLogger("TestCommonMyLoggerUiAction");
log2.info("ログのテストをしています...");
ちょっと雑ですがPREFIXで調べればロガークラスを使用している部分だけフィルタリングできますし、利用箇所で代入したprefix値のみで絞り込むこともできます。

もう少し詳細なLogger作成
もう少し色々出力したい時用にコンテキスト情報の取得処理を入れたりしています。
// ************************************************************
// Constant Variables
// ************************************************************
const Constants = Class.create();
Constants.DEFAULT_PREFIX = "MY_COMMON_LOGGER";
Constants.LOG_LEVEL_INFO = "INFO";
Constants.LOG_LEVEL_WARN = "WARN";
Constants.LOG_LEVEL_ERROR = "ERROR";
Constants.LOG_LEVEL_DEBUG = "DEBUG";
var CommonMyLogger = Class.create();
CommonMyLogger.prototype = {
/**
* オブジェクト生成時に呼ばれるクラス(コンストラクタ).
* @function initialize
* @param {Array} prefix - prefix log.
* @returns {None} return no values.
*/
initialize: function(prefix) {
// 任意のプレフィックス
this._prefix = prefix ?? Constants.DEFAULT_PREFIX;
},
// ************************************************************
// Private Functions
// ************************************************************
// 呼び出し元のコンテキストを自動で検出
_getContext: function() {
var ctx = {};
try {
ctx.user = gs.getUserName();
ctx.table = (typeof current !== 'undefined' && current) ? current.getTableName() : "";
ctx.sys_id = (typeof current !== 'undefined' && current) ? current.getUniqueValue() : "";
ctx.scope = gs.getCurrentScopeName();
ctx.script = gs.getStackTrace().split('\n')[1] || "";
} catch (e) {
// コンテキスト取得でエラーが起きてもログは続行
}
return ctx;
},
// メッセージ整形
_formatMsg: function(level, msg, ...args) {
var ctx = this._getContext();
var argStr = "";
if (args && args.length > 0) {
try {
argStr = " ARGS=" + JSON.stringify(args);
} catch (e) {}
}
return [
"[" + this._prefix + "]",
"[EXEC_ID=" + gs.generateGUID() + "]",
"[" + level + "]",
"[USER=" + ctx.user + "]",
"[TABLE=" + ctx.table + "]",
"[SYS_ID=" + ctx.sys_id + "]",
"[SCOPE=" + ctx.scope + "]",
msg,
argStr
].join(" ");
},
// ************************************************************
// Public Functions
// ************************************************************
info: function(msg, ...args) {
gs.info(this._formatMsg(Constants.LOG_LEVEL_INFO, msg, ...args));
},
warn: function(msg, ...args) {
gs.warn(this._formatMsg(Constants.LOG_LEVEL_WARN, msg, ...args));
},
error: function(msg, ...args) {
gs.error(this._formatMsg(Constants.LOG_LEVEL_ERROR, msg, ...args));
},
debug: function(msg, ...args) {
gs.debug(this._formatMsg(Constants.LOG_LEVEL_DEBUG, msg, ...args));
},
type: 'CommonMyLogger'
};
UIアクション側でこんな感じで呼び出したら
var log = new x_1603370_logtes_0.CommonMyLogger("MyUIAction");
log.debug("START", { x: 1, y: 2 });
log.info("処理中...");
log.warn("注意が必要です");
log.error("エラー発生", current);
こんな感じでいっぱい出るようになるはずですが、これくらいしかテストしていないのでエラーとかが出ても悪しからず。。。
[MyUIAction] [EXEC_ID=32ec5fbc83a1f690678dfbb6feaad39b] [INFO] [USER=admin] [TABLE=x_1603370_logtes_0_logtesttable] [SYS_ID=eaec5fbc83a1f690678dfbb6feaad367] [SCOPE=x_1603370_logtes_0] 処理中...
専用のログテーブルへの書き出しとかセッションごとのIDを自動で付与するとかオブジェクトのjson自動整形等、やろうと思えばもっと色々出来ると思いますが今回はここまで。
何かしらの参考になれば幸いです。
参考URL
以下のURLを参考にしました。有益なサイト達に感謝します。
Script Includeに定数を持たせる



