diff --git a/docs/dci-troubleshooting.md b/docs/dci-troubleshooting.md index d47cb2b..a2ef798 100644 --- a/docs/dci-troubleshooting.md +++ b/docs/dci-troubleshooting.md @@ -140,4 +140,97 @@ Then recycle any existing compute sessions - hot sessions keep the old setting u The app version is bundled into the frontend during the release, and is visible by clicking your username in the top right. -You can also determine the app version (and SASjs Version, and build time) by opening browser Development Tools and running `appinfo()` in the console. \ No newline at end of file +You can also determine the app version (and SASjs Version, and build time) by opening browser Development Tools and running `appinfo()` in the console. + +## Support Diagnostics + +The frontend sends two input tables with the startup service and with the services that execute customer-provided code - the [hook scripts](macros.md) (pre/post edit and approve hooks) and the dynamic cell dropdown programs. They are available in those services as `work.browser_info` and `work.browser_url_vars`, so a support ticket can be diagnosed from the job log without asking the user follow-up questions, and a hook can adapt to its context. Other services do not receive them. + +The services that receive the tables are: `public/startupservice`, `editors/getdata`, `editors/getdynamiccolvals`, `editors/stagedata`, `editors/loadfile`, `editors/restore` and `auditors/postdata`. + +`editors/loadfile` is the exception in practice: the app reaches it through the adapter's file-upload call (multipart), which carries no input tables, so the service - and the post edit hook it runs - does not receive them in normal use. It is on the list for completeness, and would receive them if the service were ever invoked through the ordinary request path. + +### browser_info + +A single-row table with these columns: + +| Column | Description | +|---|---| +| `url` | The URL of the Data Controller page itself (the iframe), not the document embedding it. When the editor is embedded in a report, the embedding URL is visible here. | +| `referrer` | The embedding document, from `document.referrer`. For an embedded report this is the report URL, so the embedding report can be told apart from the editor URL. | +| `timezone` | The browser's IANA timezone name, e.g. `Europe/Berlin`. | +| `tz_offset` | The browser's UTC offset in minutes, as `Date.getTimezoneOffset()` returns it (positive west of UTC, so `Europe/Berlin` in summer is -120). | +| `locale` | The browser locale, e.g. `en-GB`. | +| `dc_version` | The Data Controller build, as shown by `appinfo()`. | +| `adapter_version` | The `@sasjs/adapter` version the client was built with. | +| `browser` | The browser family, parsed from the user agent. | +| `browser_version` | The browser version. | +| `platform` | The operating system, parsed from the user agent. | +| `user_agent` | The raw `navigator.userAgent` string. | + +### browser_url_vars + +The page URL parameters as one row per parameter, so a SAS program can read a parameter by name rather than parse the `url` string: + +| Column | Description | +|---|---| +| `name` | The URL parameter name. | +| `value` | The URL parameter value. | + +Parameters from both the search string and the hash query string (Angular routes carry them after the `#`) are included; on a name collision the search string value wins. The table is sent only when the page URL has at least one parameter. + +The values in both tables are supplied by the client, so treat them as diagnostics hints rather than a security boundary. + +To see the tables, run any of the services above with debug on. The debug value depends on the path: `&_debug=131` on the Compute API and SAS 9, or `&_debug=128` on the Viya web (JES) path with `runAsTask` enabled - which is what the frontend sends there, so turning debug on in the app is enough. Either value makes the session initialisation write the tables to the job log: + +``` +NOTE: MPEINIT: work.browser_url_vars: +name=embed value=va +NOTE: MPEINIT: work.browser_info: +url=... referrer=... timezone=Europe/Berlin tz_offset=-120 locale=en-GB +dc_version=7.15.0 adapter_version=4.19.0 browser=Chrome browser_version=120.0 +platform=Linux user_agent=... +``` + +A service called directly (for instance from a URL, or by a script), or by an older frontend, has no `work.browser_info` - the log then records that fact instead. + +### Reading the tables from a hook + +A [hook script](macros.md) is `%include`d into the running service, so it shares the service's WORK library and can read the tables directly. Take an embedded editor opened at: + +``` +https://datacontroller.io/#/editor/SASHELP.CLASS?labels=true&embed=va +``` + +`browser_url_vars` then holds a row per parameter - `labels=true` and `embed=va` - so a hook can pick up either by name: + +```sas +%let labels=N; +%let embed=N; + +%if %sysfunc(exist(work.browser_url_vars)) %then %do; + proc sql noprint; + select value into :labels + from work.browser_url_vars + where name = 'labels'; + select value into :embed + from work.browser_url_vars + where name = 'embed'; + quit; +%end; +``` + +To branch on what the client reports: + +```sas +%if %sysfunc(exist(work.browser_info)) %then %do; + data _null_; + set work.browser_info; + call symputx('dc_timezone', timezone); + call symputx('dc_locale', locale); + run; +%end; +``` + +!!! warning + Guard with `%sysfunc(exist())` before reading. A service called directly, or by a frontend older than this feature, has no `work.browser_info` at all, so an unguarded `set` or `select` fails the job. \ No newline at end of file