5 JavaScript 预处理

概述

本节详细说明JavaScript预处理的相关内容。

在JavaScript预处理中请勿使用未声明的赋值操作。 使用var来声明局部变量。

JavaScript预处理

JavaScript预处理通过调用带单个参数'value'的JavaScript函数及用户提供的函数体来实现。 预处理步骤的结果是该函数返回的值,例如要执行华氏度到摄氏度的转换,需输入:

return (value - 32)  * 5 / 9

在JavaScript预处理参数中,这些代码将被服务器包装成JavaScript函数:

function (value)
       {
          return (value - 32) * 5 / 9
       }

输入参数'value'始终以string形式传递。 返回值会通过toString()方法自动强制转换为string(若转换失败,则错误信息将作为string值返回),但存在以下例外情况:

  • 返回undefined值将导致错误;
  • 返回null值会使输入值被丢弃,类似于'Custom on fail'操作中的'Discard value'预处理。

可通过抛出值/objects(通常为字符串或Error objects)来返回错误。

例如:

if (value == 0)
           throw "Zero input value"
       return 1/value

每个脚本有10秒执行超时限制(根据脚本不同,实际触发超时可能耗时更长);超时将返回错误。 同时强制执行512MB的堆内存限制。

JavaScript预处理步骤的字节码会被缓存,并在下次应用该步骤时复用。 对监控项预处理步骤的任何修改都将导致缓存脚本被重置并重新编译。

连续运行时错误(连续3次)将触发引擎重新初始化,以降低前一个脚本破坏后续脚本执行环境的可能性(该操作会记录在DebugLevel 4及以上级别的日志中)。

JavaScript预处理功能基于Duktape JavaScript引擎实现。

另请参阅:Additional JavaScript objects and global functions

在脚本中使用宏

可以在JavaScript代码中使用用户宏。 如果脚本包含用户宏,这些宏会在执行特定预处理步骤前由server/proxy解析。 请注意在前端测试预处理步骤时,宏值不会被自动获取,需要手动输入。

当宏被替换为其值时,上下文会被忽略。 宏值会按原样插入代码中,无法在将值放入JavaScript代码前进行额外转义。 请注意这可能导致某些情况下出现JavaScript错误。

在以下示例中,如果接收值超过{$THRESHOLD}宏值,将返回阈值(如果存在):

var threshold = '{$THRESHOLD}';
       return (!isNaN(threshold) && value > threshold) ? threshold : value;

示例

以下示例说明了如何使用JavaScript预处理。

每个示例包含一个简要描述、JavaScript预处理参数的函数体以及预处理步骤的结果——即函数返回的值。

示例 1:将一个数字(科学计数法转换为 integer)

将数字 "2.62128e+07" 从科学计数法转换为 integer。

return (Number(value))

函数返回的值:26212800。

示例 2:将一个数字(二进制转换为十进制)

将二进制数 "11010010" 转换为十进制数。

return(parseInt(value,2))

函数返回的值:210。

示例 3:对一个数字取整

将数字 "18.2345" 四舍五入到 2 位小数。

return(Math.round(value* 100) / 100)

函数返回的值为:18.23。

示例 4:计算 string 中的字母数量

计算string "Zabbix" 中字母的数量。

return (value.length)

函数返回的值:6。

示例 5:获取剩余时间

获取证书到期日期(格林威治时间 2022 年 2 月 12 月 12:33:56)前的剩余时间(以秒为单位)。

var split = value.split(' '),
           MONTHS_LIST = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
           month_index = ('0' + (MONTHS_LIST.indexOf(split[0]) + 1)).slice(-2),
           ISOdate = split[3] + '-' + month_index + '-' + split[1] + 'T' + split[2],
           now = Date.now();
       
       return parseInt((Date.parse(ISOdate) - now) / 1000);

函数返回的值:44380233。

示例 6:移除 JSON 属性

通过移除键为 "data_size""index_size" 的属性来修改 JSON 数据结构。

var obj=JSON.parse(value);
       
       for (i = 0; i < Object.keys(obj).length; i++) {
           delete obj[i]["data_size"];
           delete obj[i]["index_size"];
       }
       
       return JSON.stringify(obj)

函数接受的值:

[
           {
               "table_name":"history",
               "data_size":"326.05",
               "index_size":"174.34"
           },
           {
               "table_name":"history_log",
               "data_size":"6.02",
               "index_size":"3.45"
           }
       ]

函数返回的值:

[
           {
               "table_name":"history"
           },
           {
               "table_name":"history_log"
           }
       ]
示例 7: 将 Apache 状态转换为 JSON

将从web.page.get Zabbix agent 监控项接收的值(例如web.page.get[http://127.0.0.1:80/server-status?auto])转换为JSON object。

// Convert Apache status to JSON
       
       // Split the value into substrings and put these substrings into an array
       var lines = value.split('\n');
       
       // Create an empty object "output"
       var output = {};
       
       // Create an object "workers" with predefined properties
       var workers = {
           '_': 0, 'S': 0, 'R': 0, 'W': 0,
           'K': 0, 'D': 0, 'C': 0, 'L': 0,
           'G': 0, 'I': 0, '.': 0
       };
       
       // Add the substrings from the "lines" array to the "output" object as properties (key-value pairs)
       for (var i = 0; i < lines.length; i++) {
           var line = lines[i].match(/([A-z0-9 ]+): (.*)/);
       
           if (line !== null) {
               output[line[1]] = isNaN(line[2]) ? line[2] : Number(line[2]);
           }
       }
       
       // Multiversion metrics
       output.ServerUptimeSeconds = output.ServerUptimeSeconds || output.Uptime;
       output.ServerVersion = output.ServerVersion || output.Server;
       
       // Parse "Scoreboard" property to get the worker count
       if (typeof output.Scoreboard === 'string') {
           for (var i = 0; i < output.Scoreboard.length; i++) {
               var char = output.Scoreboard[i];
       
               workers[char]++;
           }
       }
       
       // Add worker data to the "output" object
       output.Workers = {
           waiting: workers['_'], starting: workers['S'], reading: workers['R'],
           sending: workers['W'], keepalive: workers['K'], dnslookup: workers['D'],
           closing: workers['C'], logging: workers['L'], finishing: workers['G'],
           cleanup: workers['I'], slot: workers['.']
       };
       
       // Return JSON string
       return JSON.stringify(output);

函数接受的输入值:

HTTP/1.1 200 OK
       Date: Mon, 27 Mar 2023 11:08:39 GMT
       Server: Apache/2.4.52 (Ubuntu)
       Vary: Accept-Encoding
       Content-Encoding: gzip
       Content-Length: 405
       Content-Type: text/plain; charset=ISO-8859-1
       
       127.0.0.1
       ServerVersion: Apache/2.4.52 (Ubuntu)
       ServerMPM: prefork
       Server Built: 2023-03-08T17:32:01
       CurrentTime: Monday, 27-Mar-2023 14:08:39 EEST
       RestartTime: Monday, 27-Mar-2023 12:19:59 EEST
       ParentServerConfigGeneration: 1
       ParentServerMPMGeneration: 0
       ServerUptimeSeconds: 6520
       ServerUptime: 1 hour 48 minutes 40 seconds
       Load1: 0.56
       Load5: 0.33
       Load15: 0.28
       Total Accesses: 2476
       Total kBytes: 8370
       Total Duration: 52718
       CPUUser: 8.16
       CPUSystem: 3.44
       CPUChildrenUser: 0
       CPUChildrenSystem: 0
       CPULoad: .177914
       Uptime: 6520
       ReqPerSec: .379755
       BytesPerSec: 3461.58
       BytesPerReq: 3461.58
       DurationPerReq: 21.2916
       BusyWorkers: 2
       IdleWorkers: 6
       Scoreboard: ____KW__..............................................................................................................................................

函数返回的输出值:

{
           "Date": "Mon, 27 Mar 2023 11:08:39 GMT",
           "Server": "Apache/2.4.52 (Ubuntu)",
           "Vary": "Accept-Encoding",
           "Encoding": "gzip",
           "Length": 405,
           "Type": "text/plain; charset=ISO-8859-1",
           "ServerVersion": "Apache/2.4.52 (Ubuntu)",
           "ServerMPM": "prefork",
           "Server Built": "2023-03-08T17:32:01",
           "CurrentTime": "Monday, 27-Mar-2023 14:08:39 EEST",
           "RestartTime": "Monday, 27-Mar-2023 12:19:59 EEST",
           "ParentServerConfigGeneration": 1,
           "ParentServerMPMGeneration": 0,
           "ServerUptimeSeconds": 6520,
           "ServerUptime": "1 hour 48 minutes 40 seconds",
           "Load1": 0.56,
           "Load5": 0.33,
           "Load15": 0.28,
           "Total Accesses": 2476,
           "Total kBytes": 8370,
           "Total Duration": 52718,
           "CPUUser": 8.16,
           "CPUSystem": 3.44,
           "CPUChildrenUser": 0,
           "CPUChildrenSystem": 0,
           "CPULoad": 0.177914,
           "Uptime": 6520,
           "ReqPerSec": 0.379755,
           "BytesPerSec": 1314.55,
           "BytesPerReq": 3461.58,
           "DurationPerReq": 21.2916,
           "BusyWorkers": 2,
           "IdleWorkers": 6,
           "Scoreboard": "____KW__..............................................................................................................................................",
           "Workers": {
               "waiting": 6,
               "starting": 0,
               "reading": 0,
               "sending": 1,
               "keepalive": 1,
               "dnslookup": 0,
               "closing": 0,
               "logging": 0,
               "finishing": 0,
               "cleanup": 0,
               "slot": 142
           }
       }