xquery-mode / cider-any

Evaluate any buffer in cider – Replaced by Oook
0 stars 1 forks source link

cider-uruk-any should be more helpful with errors #13

Open hanshuebner opened 7 years ago

hanshuebner commented 7 years ago

Right now, all exceptions are just printed using the standard cider exception handler:


  Show: Clojure Java REPL Tooling Duplicates All  (11 frames hidden)

1. Unhandled com.marklogic.xcc.exceptions.XQueryException
   com.marklogic.xcc.exceptions.XQueryException: XDMP-ARGTYPE:
   (err:XPTY0004)
   fn:substring((fn:doc("/tx-mpf/1597783.xml")/group/provider[1]/provider-group-membership[1]/group-tpisuffix-code,
   fn:doc("/tx-mpf/1597783.xml")/group/provider[1]/provider-group-membership[2]/group-tpisuffix-code),
   1, 7) -- arg1 is not of type xs:string?  [Session: user=restuser,
   cb=tx-mpf [ContentSource: user={none}, cb={none} [provider:
   address=localhost/127.0.0.1:8000, pool=1/64]]] [Client: XCC/8.0-5,
   Server: XDBC/8.0-4.2] in /eval, on line 19 expr:
   fn:substring((fn:doc("/tx-mpf/1597783.xml")/group/provider[1]/provider-group-membership[1]/group-tpisuffix-code,
   fn:doc("/tx-mpf/1597783.xml")/group/provider[1]/provider-group-membership[2]/group-tpisuffix-code),
   1, 7), in
   local:validate-with-tpi(fn:doc("/claims/10150330.xml")/c:claim/c:access-point/c:medicaid-id/text(),
   fn:doc("/claims/10150330.xml")/c:claim) in /eval, on line 63 expr:
   fn:substring((fn:doc("/tx-mpf/1597783.xml")/group/provider[1]/provider-group-membership[1]/group-tpisuffix-code,
   fn:doc("/tx-mpf/1597783.xml")/group/provider[1]/provider-group-membership[2]/group-tpisuffix-code),
   1, 7)

ServerExceptionHandler.java:   34  com.marklogic.xcc.impl.handlers.ServerExceptionHandler/handleResponse
EvalRequestController.java:   96  com.marklogic.xcc.impl.handlers.EvalRequestController/serverDialog

It would be nice if the XQuery stacktrace was displayed instead. and if there was an easy way to navigate to the XQuery error location from there.

proofit404 commented 7 years ago

If in /eval, on line 19 expr part of xquery stacktrace pointed to the right document location, it is possible to write compilation-minor-mode compatible regex. It's possible to navigate with next-error and previous-error keys.

Is it what are you looking for?

hanshuebner commented 7 years ago

Exactly, the error location in the XQuery evaluator stack trace is accurate and currently, I'm locating the error manually by looking at the on line 63 expr lines. Also, it would be good if the XQuery stack traces would be alone, not mixed with the Clojure stack traces. If that is possible at all.

proofit404 commented 7 years ago

In the branch error-buffer following behavior is implemented:

xquery version "1.0-ml";
module namespace hello = "helloworld";

declare function helloworld()
{
  <foo>
};
XQueryException com.marklogic.xcc.exceptions.XQueryException: XDMP-BADCHAR: (err:XPST0003) Unexpected character found '}' (0x007d)
 [Session: user=proofit404, cb=TutorialDB [ContentSource: user=proofit404, cb=TutorialDB [provider: address=localhost/127.0.0.1:8889, pool=1/64]]]
 [Client: XCC/8.0-5, Server: XDBC/8.0-5.8]
on line 7
expr:    com.marklogic.xcc.impl.handlers.ServerExceptionHandler.handleResponse (ServerExceptionHandler.java:34)

Now things becomes more interesting when we speak about errors inside documents uploaded to the MarkLogic server. For example syntax error can be placed inside module on the other server. In my installation I store xquery modules in the /data/ directory on the remote server. Lets upload xquery module from previous example to the /data/e/test.xqy to the marklogic host.

Now we open another xquery file localy

xquery version "1.0-ml";
import module namespace hw="helloworld" at "/e/test.xqy";

hw:helloworld()
XQueryException com.marklogic.xcc.exceptions.XQueryException: XDMP-BADCHAR: (err:XPST0003) Unexpected character found '}' (0x007d)
 [Session: user=proofit404, cb=TutorialDB [ContentSource: user=proofit404, cb=TutorialDB [provider: address=localhost/127.0.0.1:8889, pool=1/64]]]
 [Client: XCC/8.0-5, Server: XDBC/8.0-5.8]
in /e/test.xqy, on line 7
expr:    com.marklogic.xcc.impl.handlers.ServerExceptionHandler.handleResponse (ServerExceptionHandler.java:34)

Please give it a try and let me know if any this is missing in this feature.

m-g-r commented 7 years ago

Hi, this starts to look nice! For now, there seem to be some problems.

But all together, this look promising. Good work! Maybe make the messages more readable by moving less interesting information down. Have a look at:

XQueryException com.marklogic.xcc.exceptions.XQueryException: XDMP-NOTANODE: (err:XPTY0019) 23 | 23 -- 23 is not a node
 [Session: user=admin, cb={default} [ContentSource: user=admin, cb={none} [provider: address=localhost/127.0.0.1:8021, pool=1/64]]]
 [Client: XCC/8.0-5, Server: XDBC/8.0-5.5]
on line 4
expr: 23 | 23  com.marklogic.xcc.impl.handlers.ServerExceptionHandler.handleResponse (ServerExceptionHandler.java:34)

The interesting part only starts after "XQueryException com.marklogic.xcc.exceptions.XQueryException: ", and the [Session...][Client...] lines cold be moved below the error message itself, right?

Bye, Max

proofit404 commented 7 years ago

Hi!

First of all I want to describe how it was implemented.

We have cider-any-eval-handler which will take error reported by clojure uruk library. Error here is simply a string with traceback.

We show error buffer in any case without additional preprocessing.

Then if there is lines like "on line <num>" or "in <doc>, on line <num>" we will treat them as links to documents and support next or previous errors navigation.

Pretty simple, right?

Now let me explain each item in your list:

  1. If there is no helpful information after expr: ..., that mean uruk library report it this way and there is nothing we can do about it. Error navigation based of line marker not expr anyway.
  2. I will try to failback to previous behavior, if error was an empty string. But I'm not sure cider will process it correctly, since it use same error value as my handler do.

2.1. Please, submit reproducible document if possible. You can skip it minimization.

  1. I will read xdmp:modules-database() documentation careful, hope it is possible to use it in remote modules navigation.

3.1. I don't think we need to move xdbc logic into cider-any-uruk. At least until we finish this branch.

Finally on error content modification. I think if we would modify it, we must do it in the clojure layer, when exception object is accessible. Not in Emacs Lisp when it only a string with new lines. I'll try to figure out if it possible based on current uruk code base.

Regards, Artem.

proofit404 commented 7 years ago

Hello guys, I'm stuck :(

Expected usage

I'm trying to implement content access for MarkLogic modules. While navigate in the error buffer I want to see the actual position in the module, which triggers error. For example we have this file:

xquery version "1.0-ml";
import module namespace sec="http://marklogic.com/xdmp/security" at "/MarkLogic/security.xqy";

sec:user-get-roles("Jim")

Now I type C-c C-c. Following error buffer shows up:

XQueryException com.marklogic.xcc.exceptions.XQueryException: SEC-USERDNE: (err:FOER0000) User does not exist: sec:user-name = Jim
 [Session: user=proofit404, cb=TutorialDB [ContentSource: user=proofit404, cb=TutorialDB [provider: address=localhost/127.0.0.1:8889, pool=1/64]]]
 [Client: XCC/8.0-5, Server: XDBC/8.0-5.8]
in /MarkLogic/security.xqy, on line 3612
expr:  ,
in get-element("http://marklogic.com/xdmp/security", "sec:user", "sec:user-name", "Jim", "SEC-USERDNE")
in /MarkLogic/security.xqy, on line 1265
expr:  ,
in sec:user-get-roles("Jim")
on line 4
expr:    com.marklogic.xcc.impl.handlers.ServerExceptionHandler.handleResponse (ServerExceptionHandler.java:34)

We see three frames of traceback for this error. The first one stays in the /MarkLogic/security.xqy module. When I call next-error command cursor will stays at front of the first in ... expression and tries to open security module. This module stored in the modules database and I can obtain it with this xquery:

xdmp:document-get("/opt/MarkLogic/Modules/MarkLogic/security.xqy")

But how do I know this full path to the module? I try to google this solution for two days with out any success...

Then when I call next-error one more time I expect cursor moves its position in the security buffer from 3612 to the 1265 line.

After next call to next-error command we will stay inside our file in the line 4.

All this thing is working except I can't figure out how to obtain module content from module uri.

Modules database setting

Also there are two possible scenarios according to "modules database" setting. It is related to modules which were uploaded ourselves. If we set "modules database" setting to the "(file system)", our modules will be loaded from file system root. To resolve those modules we need something like

if (xdmp:modules-database() = 0)
then
  xdmp:document-get(fn:concat(xdmp:modules-root(), "/MarkLogic/security.xqy"))
else
  ...

But in general "modules database" setting will be set to something like "Modules" so our modules will be uploaded to this database too. I've tried to do something like this:

declare variable $module :=
  <module>
    <uri>/MarkLogic/security.xqy</uri>
  </module>;

let $mdb := xdmp:modules-database()

xdmp:eval(fn:concat('xdmp:document-get("', $module/uri, '")'),
          (),
          <options xmlns="xdmp:eval">
            <database>{$mdb}</database>
          </options>)

But it doesn't do what I expect.

Any suggestions?

Regards, Artem.

m-g-r commented 7 years ago

Hi Artem,

Short answer: the Modules of the Marklogic installation itself are special. Try with a user Module that you've added yourself; it should work for that case.

Please have another look at how MarkLogic resolves paths on module loading: https://docs.marklogic.com/guide/app-dev/import_modules#id_29407

The problem now are:

My perspective on priorities:

Cheers, Max

m-g-r commented 7 years ago

PS: fn:concat(xdmp:modules-root(), "/MarkLogic/security.xqy") might lead to a double slash.

proofit404 commented 7 years ago

As we say in Russia:

Either I'm a fool, or my skis not slide.

I've spent yet another two days trying to import a module from the modules database :(

I've tried every possible combination of xdmp:document-insert, xdmp:document-load, xdmp:permission. I just can't create importable module for my test purposes.

It will be very nice if you can write short instruction for dummies how to create importable module, how to upload it in to modules database, how to import it.

On progress

I introduced configurable variable for MarkLogic installation path. By default its value is "/opt/MarkLogic/". I need to note that Windows support will require slightly more efforts to implement. Now when we navigates through error list for each module uri we tries:

1) Find this module in /path/to/MarkLogic/Modules/uri/part/of/path.xqy This works reasonable well, if you setup this variable correctly. 2) If App Server uses (file system) as its modules storage, we search given module on file system. This technique was discussed earlier. 3) If App Server uses Modules database, we will get this module content using fn:doc.

I need to test last condition, by I failed to build necessary environment for it.

Regards, Artem.

m-g-r commented 7 years ago

Hi Artem,

Thanks that sounds quite. I'll make you a test example later. No worries, sometimes things behave strangely. Also I will give you feedback about the possible renaming etc.

Cheers Max

m-g-r commented 7 years ago

Hi,

here is a complete example.

A module: foo-module.xqy.txt

XQuery code to upload to MarkLogic when talking directly to the Modules database: foo-module-upload.xqy.txt

XQuery code to upload to MarkLogic when talking directly to another database database: foo-module-upload-from-content-base.xqy.txt

XQuery code to show the module when talking directly to the Modules database: foo-module-show.xqy.txt

XQuery code to show the module when talking to antother database: foo-module-show-from-content-base.xqy.txt

In general: Better not use xdmp:document-get()``, as we never want to fetch files from the web (i.e., over http). Either usedocto fetch from a xml database or usexdmp:filesystem-file``` to retrieve files form the filesystem of the server.

Hope that helps, Max

proofit404 commented 7 years ago

I've followed your recommendations and it looks like it finally works. Thanks!!

Please check that it works in your environment too.

I still can't reproduce the case with empty error buffer. Maybe you will find those circumstances later.

NOTE: you should use error-buffer branch in the Oook repository since we've moved the code and not the issues.

m-g-r commented 7 years ago

Thank you! That sounds great. Currently, I'm very busy with a project and cannot change the tooling right now. But I noticed your code changes and I'm eager to use it. Thanks for already making the oook-selector repository and updating the code!

Oh, could you post screenshot of the error-buffer output? Did you rearrange the output a bit as suggested at the end of my comment in https://github.com/xquery-mode/cider-any/issues/13#issuecomment-254154280?

By the way, for said project I use all these facilities. Nice to use, also when talking to several MarkLogic instances at the same time. And also some queries are not only more convenient to do from Emacs than MarkLogic's Query Console but also some huge queries I get in below a second of response time while the Query Console takes 4-7 seconds. Isn't that nice? (I'm guessing that the Javascript does some post-processing for nice presentation that takes longer.)

Cheers, Max

proofit404 commented 7 years ago

Oh, could you post screenshot of the error-buffer output?

error-buffer

Did you rearrange the output a bit as suggested at the end of my comment in #13 (comment)?

Not yet, but I found the way which can probably work out. If this research will be successful we will have new output format soon.

By the way I'm glad you're like it!

proofit404 commented 7 years ago

Good morning!

I rearrange the output as suggested at the end of your comment.

Basically I reimplement exception representation from scratch in the clojure handler. It supersedes this and that methods.

Please test if it works for you and if it fits necessary information layout.

P.S. my clojure skills are weak so catch code looks not so good.

m-g-r commented 7 years ago

Very nice! I just have started to use it, so didn't have an in-depth look. So far very nice! Is there a key to show also the full Java stack trace? Just in case... Cheers, Max

proofit404 commented 7 years ago

Yes, it's possible. I will add it at the end of buffer.

proofit404 commented 7 years ago

Java stack trace now looks like this java-stacktrace There is a line at the end of the error buffer. It magically appended to original message somewhere outside of oook exception handler. I suspect this happens because we throw new exception within try/catch block. It mostly a cosmetic trouble so I don't research it too much.