]> granicus.if.org Git - icinga2/blob - doc/20-script-debugger.md
Merge pull request #6239 from Icinga/fix/windows-check-memory
[icinga2] / doc / 20-script-debugger.md
1 # Script Debugger <a id="script-debugger"></a>
2
3 You can run the Icinga 2 daemon with the `-X` (`--script-debugger`)
4 parameter to enable the script debugger:
5
6     # icinga2 daemon -X
7
8 When an exception occurs or the [debugger](17-language-reference.md#breakpoints)
9 keyword is encountered in a user script, Icinga 2 launches a console that
10 allows the user to debug the script.
11
12 You can also attach the script debugger to the [configuration validation](11-cli-commands.md#config-validation):
13
14     # icinga2 daemon -C -X
15
16 Here is a list of common errors which can be diagnosed with the script debugger:
17
18 * Configuration errors e.g. [apply rules](03-monitoring-basics.md#using-apply)
19 * Errors in user-defined [functions](17-language-reference.md#functions)
20
21 ## Debugging Configuration Errors <a id="script-debugger-config-errors"></a>
22
23 The following example illustrates the problem of a service [apply rule](03-monitoring-basics.md#using-apply-for)
24 which expects a dictionary value for `config`, but the host custom attribute only
25 provides a string value:
26
27     object Host "script-debugger-host" {
28       check_command = "icinga"
29
30       vars.http_vhosts["example.org"] = "192.168.1.100" // a string value
31     }
32
33     apply Service for (http_vhost => config in host.vars.http_vhosts) {
34       import "generic-service"
35
36       vars += config // expects a dictionary
37
38       check_command = "http"
39     }
40
41 The error message on config validation will warn about the wrong value type,
42 but does not provide any context which objects are affected.
43
44 Enable the script debugger and run the config validation:
45
46     # icinga2 daemon -C -X
47
48     Breakpoint encountered in /etc/icinga2/conf.d/services.conf: 59:67-65:1
49     Exception: Error: Error while evaluating expression: Cannot convert value of type 'String' to an object.
50     Location:
51     /etc/icinga2/conf.d/services.conf(62):   check_command = "http"
52     /etc/icinga2/conf.d/services.conf(63):
53     /etc/icinga2/conf.d/services.conf(64):   vars += config
54                                              ^^^^^^^^^^^^^^
55     /etc/icinga2/conf.d/services.conf(65): }
56     /etc/icinga2/conf.d/services.conf(66):
57     You can inspect expressions (such as variables) by entering them at the prompt.
58     To leave the debugger and continue the program use "$continue".
59     <1> =>
60
61 You can print the variables `vars` and `config` to get an idea about
62 their values:
63
64     <1> => vars
65     null
66     <2> => config
67     "192.168.1.100"
68     <3> =>
69
70 The `vars` attribute has to be a dictionary. Trying to set this attribute to a string caused
71 the error in our configuration example.
72
73 In order to determine the name of the host where the value of the `config` variable came from
74 you can inspect attributes of the service object:
75
76     <3> => host_name
77     "script-debugger-host-01"
78     <4> => name
79     "http"
80
81 Additionally you can view the service object attributes by printing the value of `this`.
82
83 ## Using Breakpoints <a id="script-debugger-breakpoints"></a>
84
85 In order to halt execution in a script you can use the `debugger` keyword:
86
87     object Host "script-debugger-host-02" {
88       check_command = "dummy"
89       check_interval = 5s
90
91       vars.dummy_text = {{
92         var text = "Hello from " + macro("$name$")
93         debugger
94         return text
95       }}
96     }
97
98 Icinga 2 will spawn a debugger console every time the function is executed:
99
100     # icinga2 daemon -X
101     ...
102     Breakpoint encountered in /etc/icinga2/tests/script-debugger.conf: 7:5-7:12
103     You can inspect expressions (such as variables) by entering them at the prompt.
104     To leave the debugger and continue the program use "$continue".
105     <1> => text
106     "Hello from script-debugger-host-02"
107     <2> => $continue
108
109
110 ## Debugging API Filters <a id="script-debugger-api-filters"></a>
111
112 Queries against the [Icinga 2 REST API](12-icinga2-api.md#icinga2-api) can use
113 filters, just like available in `assign where` expressions. If these filters cause
114 an internal error, they return an empty result to the caller.
115
116 In order to analyse these server-side errors, you can use the script debugger.
117
118 The following example tries filter for all host objects where the custom attribute
119 `os` is set. There are various possibilities to check that, one of them would be
120 `host.vars.os != ""`. Another idea is to use the [contains](18-library-reference.md#dictionary-contains) method on the custom
121 attribute dictionary like this: `host.vars.contains("os")`.
122
123 ```
124 $ curl -k -s -u root:icinga -H 'Accept: application/json' -H 'X-HTTP-Method-Override: GET' \
125  -X POST 'https://localhost:5665/v1/objects/services' \
126  -d '{ "filter": "host.vars.contains(\"os\")", "attrs": [ "__name" ], "joins": [ "host.name", "host.vars" ], "pretty": true }'
127 ```
128
129 This will fail on all hosts which don't have any custom attribute specified.
130
131 ```
132 # icinga2 daemon -X
133
134 Breakpoint encountered.
135 Exception: Error: Argument is not a callable object.
136 Location: in <API query>: 1:0-1:23
137 You can inspect expressions (such as variables) by entering them at the prompt.
138 To leave the debugger and continue the program use "$continue".
139
140 <1> => this.host
141
142 ...
143
144         vars = null
145
146 <2> => $continue
147 ```
148
149 By definition, a type method can only be invoked on an actual object.
150
151 In order to stay safe, add more checks to the API filter:
152
153 - `host.vars && host.vars.contains("os")` or
154 - `host.vars && typeof(host.vars) == Dictionary && host.vars.contains("os")`
155
156 Example:
157
158 ```
159 $ curl -k -s -u root:icinga -H 'Accept: application/json' -H 'X-HTTP-Method-Override: GET' \
160  -X POST 'https://localhost:5665/v1/objects/services' \
161  -d '{ "filter": "host.vars && typeof(host.vars) == Dictionary && host.vars.contains(\"os\")", "attrs": [ "__name" ], "joins": [ "host.name", "host.vars" ], "pretty": true }'
162 ```