4 JavaScript 预处理

概述

本节提供 JavaScript 预处理的详细信息。

JavaScript 预处理

JavaScript 预处理是通过调用具有单个参数“值”和用户提供的函数体的 JavaScript 函数来完成的。 预处理步骤的结果是从这个函数返回的值,例如,要执行华氏到摄氏度的转换,用户必须输入:

  1. return (value - 32) * 5 / 9

在 JavaScript 预处理参数中,将被服务器包装成一个 JavaScript 函数:

  1. function (value)
  2. {
  3. return (value - 32) * 5 / 9
  4. }

输入参数“值”始终作为字符串传递。 返回值通过 ToString() 方法自动强制转换为字符串(如果失败,则错误作为字符串值返回),但有一些例外:

  • 返回未定义的值将导致错误
  • 返回空值将导致输入值被丢弃,很像“Custom on fail”操作中的“丢弃值”预处理。

可以通过抛出值/对象(通常是字符串或错误对象)来返回错误。

例子:

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

每个脚本都有 10 秒的执行超时(根据脚本的不同,触发超时可能需要更长的时间); 超过它会返回错误。 强制执行 64 兆字节的堆限制。

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

连续运行时失败(连续 3 次)将导致引擎重新初始化,以减少一个脚本破坏下一个脚本的执行环境的可能性(此操作使用 DebugLevel 4 及更高级别记录)。

JavaScript 预处理是用 Duktape 实现的 (https://duktape.org/) JavaScript 引擎。

参考: 另外的 JavaScript 对象和全局函数

在脚本中使用宏

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

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

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

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

Examples

The following examples illustrate how you can use JavaScript preprocessing. Each example contains a brief description, a function body for JavaScript preprocessing parameters, and the preprocessing step result (value accepted by the function → value returned by the function).

Example 1: Convert number (scientific notation to integer)

Convert a number from scientific notation to an integer.

  1. return (Number(value))

Result: 2.62128e+07 → 26212800

Example 2: Convert number (binary to decimal)

Convert a binary number to a decimal number.

  1. return(parseInt(value,2))

Result: 11010010 → 210

Example 3: Round a number

Round a number to 2 digits.

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

Result: 18.2345 → 18.23

Example 4: Count letters in a string

Count the number of letters in a string.

  1. return (value.length)

Result: “zabbix” → 6

Example 5: Get time remaining

Get the remaining time (in seconds) until the expiration date of a certificate.

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

Result: Feb 12 12:33:56 2022 GMT → 44380233

Example 6: Modify JSON (remove properties)

Modify a JSON data structure by removing any properties with the key "data_size" or "index_size".

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

Value accepted by the function:

  1. [
  2. {
  3. "table_name":"history",
  4. "data_size":"326.05",
  5. "index_size":"174.34"
  6. },
  7. {
  8. "table_name":"history_log",
  9. "data_size":"6.02",
  10. "index_size":"3.45"
  11. }
  12. ]

Value returned by the function:

  1. [
  2. {
  3. "table_name":"history"
  4. },
  5. {
  6. "table_name":"history_log"
  7. }
  8. ]
Example 7: Convert Apache status to JSON

Convert the value received from a web.page.get Zabbix agent item (e.g., web.page.get[http://127.0.0.1:80/server-status?auto\]) to a JSON object.

  1. // Convert Apache status to JSON
  2. // Split the value into substrings and put these substrings into an array
  3. var lines = value.split('\n');
  4. // Create an empty object "output"
  5. var output = {};
  6. // Create an object "workers" with predefined properties
  7. var workers = {
  8. '_': 0, 'S': 0, 'R': 0, 'W': 0,
  9. 'K': 0, 'D': 0, 'C': 0, 'L': 0,
  10. 'G': 0, 'I': 0, '.': 0
  11. };
  12. // Add the substrings from the "lines" array to the "output" object as properties (key-value pairs)
  13. for (var i = 0; i < lines.length; i++) {
  14. var line = lines[i].match(/([A-z0-9 ]+): (.*)/);
  15. if (line !== null) {
  16. output[line[1]] = isNaN(line[2]) ? line[2] : Number(line[2]);
  17. }
  18. }
  19. // Multiversion metrics
  20. output.ServerUptimeSeconds = output.ServerUptimeSeconds || output.Uptime;
  21. output.ServerVersion = output.ServerVersion || output.Server;
  22. // Parse "Scoreboard" property to get the worker count
  23. if (typeof output.Scoreboard === 'string') {
  24. for (var i = 0; i < output.Scoreboard.length; i++) {
  25. var char = output.Scoreboard[i];
  26. workers[char]++;
  27. }
  28. }
  29. // Add worker data to the "output" object
  30. output.Workers = {
  31. waiting: workers['_'], starting: workers['S'], reading: workers['R'],
  32. sending: workers['W'], keepalive: workers['K'], dnslookup: workers['D'],
  33. closing: workers['C'], logging: workers['L'], finishing: workers['G'],
  34. cleanup: workers['I'], slot: workers['.']
  35. };
  36. // Return JSON string
  37. return JSON.stringify(output);

Value accepted by the function:

  1. HTTP/1.1 200 OK
  2. Date: Mon, 27 Mar 2023 11:08:39 GMT
  3. Server: Apache/2.4.52 (Ubuntu)
  4. Vary: Accept-Encoding
  5. Content-Encoding: gzip
  6. Content-Length: 405
  7. Content-Type: text/plain; charset=ISO-8859-1
  8. 127.0.0.1
  9. ServerVersion: Apache/2.4.52 (Ubuntu)
  10. ServerMPM: prefork
  11. Server Built: 2023-03-08T17:32:01
  12. CurrentTime: Monday, 27-Mar-2023 14:08:39 EEST
  13. RestartTime: Monday, 27-Mar-2023 12:19:59 EEST
  14. ParentServerConfigGeneration: 1
  15. ParentServerMPMGeneration: 0
  16. ServerUptimeSeconds: 6520
  17. ServerUptime: 1 hour 48 minutes 40 seconds
  18. Load1: 0.56
  19. Load5: 0.33
  20. Load15: 0.28
  21. Total Accesses: 2476
  22. Total kBytes: 8370
  23. Total Duration: 52718
  24. CPUUser: 8.16
  25. CPUSystem: 3.44
  26. CPUChildrenUser: 0
  27. CPUChildrenSystem: 0
  28. CPULoad: .177914
  29. Uptime: 6520
  30. ReqPerSec: .379755
  31. BytesPerSec: 3461.58
  32. BytesPerReq: 3461.58
  33. DurationPerReq: 21.2916
  34. BusyWorkers: 2
  35. IdleWorkers: 6
  36. Scoreboard: ____KW__..............................................................................................................................................

Value returned by the function:

  1. {
  2. "Date": "Mon, 27 Mar 2023 11:08:39 GMT",
  3. "Server": "Apache/2.4.52 (Ubuntu)",
  4. "Vary": "Accept-Encoding",
  5. "Encoding": "gzip",
  6. "Length": 405,
  7. "Type": "text/plain; charset=ISO-8859-1",
  8. "ServerVersion": "Apache/2.4.52 (Ubuntu)",
  9. "ServerMPM": "prefork",
  10. "Server Built": "2023-03-08T17:32:01",
  11. "CurrentTime": "Monday, 27-Mar-2023 14:08:39 EEST",
  12. "RestartTime": "Monday, 27-Mar-2023 12:19:59 EEST",
  13. "ParentServerConfigGeneration": 1,
  14. "ParentServerMPMGeneration": 0,
  15. "ServerUptimeSeconds": 6520,
  16. "ServerUptime": "1 hour 48 minutes 40 seconds",
  17. "Load1": 0.56,
  18. "Load5": 0.33,
  19. "Load15": 0.28,
  20. "Total Accesses": 2476,
  21. "Total kBytes": 8370,
  22. "Total Duration": 52718,
  23. "CPUUser": 8.16,
  24. "CPUSystem": 3.44,
  25. "CPUChildrenUser": 0,
  26. "CPUChildrenSystem": 0,
  27. "CPULoad": 0.177914,
  28. "Uptime": 6520,
  29. "ReqPerSec": 0.379755,
  30. "BytesPerSec": 1314.55,
  31. "BytesPerReq": 3461.58,
  32. "DurationPerReq": 21.2916,
  33. "BusyWorkers": 2,
  34. "IdleWorkers": 6,
  35. "Scoreboard": "____KW__..............................................................................................................................................",
  36. "Workers": {
  37. "waiting": 6,
  38. "starting": 0,
  39. "reading": 0,
  40. "sending": 1,
  41. "keepalive": 1,
  42. "dnslookup": 0,
  43. "closing": 0,
  44. "logging": 0,
  45. "finishing": 0,
  46. "cleanup": 0,
  47. "slot": 142
  48. }
  49. }