95 lines
3.6 KiB
Plaintext
95 lines
3.6 KiB
Plaintext
[[painless-debugging]]
|
|
=== Painless Debugging
|
|
|
|
==== Debug.Explain
|
|
|
|
Painless doesn't have a
|
|
https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop[REPL]
|
|
and while it'd be nice for it to have one day, it wouldn't tell you the
|
|
whole story around debugging painless scripts embedded in Elasticsearch because
|
|
the data that the scripts have access to or "context" is so important. For now
|
|
the best way to debug embedded scripts is by throwing exceptions at choice
|
|
places. While you can throw your own exceptions
|
|
(`throw new Exception('whatever')`), Painless's sandbox prevents you from
|
|
accessing useful information like the type of an object. So Painless has a
|
|
utility method, `Debug.explain` which throws the exception for you. For
|
|
example, you can use {ref}/search-explain.html[`_explain`] to explore the
|
|
context available to a {ref}/query-dsl-script-query.html[script query].
|
|
|
|
[source,js]
|
|
---------------------------------------------------------
|
|
PUT /hockey/player/1?refresh
|
|
{"first":"johnny","last":"gaudreau","goals":[9,27,1],"assists":[17,46,0],"gp":[26,82,1]}
|
|
|
|
POST /hockey/player/1/_explain
|
|
{
|
|
"query": {
|
|
"script": {
|
|
"script": "Debug.explain(doc.goals)"
|
|
}
|
|
}
|
|
}
|
|
---------------------------------------------------------
|
|
// CONSOLE
|
|
// TEST[s/_explain/_explain?error_trace=false/ catch:/painless_explain_error/]
|
|
// The test system sends error_trace=true by default for easier debugging so
|
|
// we have to override it to get a normal shaped response
|
|
|
|
Which shows that the class of `doc.first` is
|
|
`org.elasticsearch.index.fielddata.ScriptDocValues.Longs` by responding with:
|
|
|
|
[source,js]
|
|
---------------------------------------------------------
|
|
{
|
|
"error": {
|
|
"type": "script_exception",
|
|
"to_string": "[1, 9, 27]",
|
|
"painless_class": "org.elasticsearch.index.fielddata.ScriptDocValues.Longs",
|
|
"java_class": "org.elasticsearch.index.fielddata.ScriptDocValues$Longs",
|
|
...
|
|
},
|
|
"status": 400
|
|
}
|
|
---------------------------------------------------------
|
|
// TESTRESPONSE[s/\.\.\./"script_stack": $body.error.script_stack, "script": $body.error.script, "lang": $body.error.lang, "caused_by": $body.error.caused_by, "root_cause": $body.error.root_cause, "reason": $body.error.reason/]
|
|
|
|
You can use the same trick to see that `_source` is a `LinkedHashMap`
|
|
in the `_update` API:
|
|
|
|
[source,js]
|
|
---------------------------------------------------------
|
|
POST /hockey/player/1/_update
|
|
{
|
|
"script": "Debug.explain(ctx._source)"
|
|
}
|
|
---------------------------------------------------------
|
|
// CONSOLE
|
|
// TEST[continued s/_update/_update?error_trace=false/ catch:/painless_explain_error/]
|
|
|
|
The response looks like:
|
|
|
|
[source,js]
|
|
---------------------------------------------------------
|
|
{
|
|
"error" : {
|
|
"root_cause": ...,
|
|
"type": "illegal_argument_exception",
|
|
"reason": "failed to execute script",
|
|
"caused_by": {
|
|
"type": "script_exception",
|
|
"to_string": "{gp=[26, 82, 1], last=gaudreau, assists=[17, 46, 0], first=johnny, goals=[9, 27, 1]}",
|
|
"painless_class": "java.util.LinkedHashMap",
|
|
"java_class": "java.util.LinkedHashMap",
|
|
...
|
|
}
|
|
},
|
|
"status": 400
|
|
}
|
|
---------------------------------------------------------
|
|
// TESTRESPONSE[s/"root_cause": \.\.\./"root_cause": $body.error.root_cause/]
|
|
// TESTRESPONSE[s/\.\.\./"script_stack": $body.error.caused_by.script_stack, "script": $body.error.caused_by.script, "lang": $body.error.caused_by.lang, "caused_by": $body.error.caused_by.caused_by, "reason": $body.error.caused_by.reason/]
|
|
// TESTRESPONSE[s/"to_string": ".+"/"to_string": $body.error.caused_by.to_string/]
|
|
|
|
Once you have a class you can go to <<painless-api-reference>> to see a list of
|
|
available methods.
|