123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- [[modules-scripting-painless-debugging]]
- === Painless Debugging
- experimental[The Painless scripting language is new and is still marked as experimental. The syntax or API may be changed in the future in non-backwards compatible ways if required.]
- ==== 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 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 the <<search-explain>> to explore the context available to
- a <<query-dsl-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",
- "class": "org.elasticsearch.index.fielddata.ScriptDocValues$Longs",
- "to_string": "[1, 9, 27]",
- ...
- },
- "status": 500
- }
- ---------------------------------------------------------
- // 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 `java.util.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",
- "class": "java.util.LinkedHashMap",
- "to_string": "{gp=[26, 82, 1], last=gaudreau, assists=[17, 46, 0], first=johnny, goals=[9, 27, 1]}",
- ...
- }
- },
- "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/]
- // TODO we should build some javadoc like mashup so people don't have to jump through these hoops.
- Once you have the class of an object you can go
- https://github.com/elastic/elasticsearch/tree/{branch}/modules/lang-painless/src/main/resources/org/elasticsearch/painless[here]
- and check the available methods. Painless uses a strict whitelist to prevent
- scripts that don't work well with Elasticsearch and all whitelisted methods
- are listed in a file named after the package of the object (everything before
- the last `.`). So `java.util.Map` is listed in a file named `java.util.txt`
- starting on the line that looks like `class Map -> java.util.Map {`.
- With the list of whitelisted methods in hand you can turn to either
- https://docs.oracle.com/javase/8/docs/api/[Javadoc],
- https://github.com/elastic/elasticsearch/tree/{branch}[Elasticsearch's source tree]
- or, for whitelisted methods ending in `*`, the
- https://github.com/elastic/elasticsearch/blob/{branch}/modules/lang-painless/src/main/java/org/elasticsearch/painless/Augmentation.java[Augmentation]
- class.
|