diff --git a/content/feed/support-diagnostics/index.md b/content/feed/support-diagnostics/index.md new file mode 100644 index 0000000..9f6f5dd --- /dev/null +++ b/content/feed/support-diagnostics/index.md @@ -0,0 +1,158 @@ +--- +title: 'Support Diagnostics: browser_info and browser_url_vars' +description: Data Controller sends two input tables with the startup service and with every service that runs customer code - the browser context and the page URL parameters. A support ticket can be answered from the job log, and a hook can read them. +date: '2026-09-27 09:00:00' +author: 'Data Controller' +authorLink: https://www.linkedin.com/showcase/data-controller-for-sas +tags: + - Announcements +previewImg: './support-diagnostics.jpeg' +--- + +# Support Diagnostics: browser_info and browser_url_vars + +A support ticket usually starts with a round of questions. Which browser? Which timezone? Which build? What was in the URL? Data Controller now answers them itself. The frontend sends two input tables - `browser_info` and `browser_url_vars` - with the startup service and with every service that runs customer-provided code, so the context of a session is in the job log before anyone asks for it, and a hook script can read it. + +This ships with the next Data Controller release. + +## The two tables + +Both are ordinary input tables on the request: the adapter turns each array in the payload into a table in the service's WORK library, so they arrive as `work.browser_info` and `work.browser_url_vars`. + +### browser_info + +A single row, describing the client that made the request: + +| Column | What it holds | +|---|---| +| `url` | The URL of the Data Controller page itself (the iframe), not the document embedding it - so an embedded editor is distinguishable from a standalone one. | +| `referrer` | The embedding document, from `document.referrer`. For an embedded report this is the report URL. | +| `timezone` | The browser's IANA timezone, 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 `appinfo()` reports it. | +| `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. | +| `user_agent` | The raw `navigator.userAgent` string. | + +### browser_url_vars + +One row per URL parameter: + +| Column | What it holds | +|---|---| +| `name` | The parameter name. | +| `value` | The parameter value. | + +Parameters are read from both the search string and the hash query string, because Angular routes carry them after the `#`. Where the same name appears in both, the search string wins. The table is sent only when the page URL has at least one parameter. + +## Which services receive them + +| Service | When | +|---|---| +| `public/startupservice` | Once per session, so every job log carries the session context | +| `editors/getdata` | The PRE_EDIT_HOOK | +| `editors/stagedata` | The POST_EDIT_HOOK, through the loader | +| `editors/restore` | The POST_EDIT_HOOK, through the loader | +| `editors/getdynamiccolvals` | The dynamic cell dropdown programs | +| `auditors/postdata` | The PRE_APPROVE_HOOK and POST_APPROVE_HOOK | +| `editors/loadfile` | The POST_EDIT_HOOK - see the caveat below | + +Those are the services that run customer code. The viewer's `viewlibs`, `viewtables` and `viewdata`, the metadata services and `usernav` receive neither table, so the high-frequency calls stay lean. + +## Reading them in a hook + +A hook script 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` - and a hook can read 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; +``` + +Or branch on what the user's browser reports: + +```sas +data _null_; + set work.browser_info; + call symputx('dc_timezone', timezone); + call symputx('dc_locale', locale); +run; +``` + +Note the `exist()` guard. 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` would fail the job. Guard first, then read. + +## In the job log + +Turn debug on and the session initialisation writes both tables to the log, so a ticket can be diagnosed without a second round of questions: + +``` +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=... adapter_version=... browser=Chrome browser_version=... +platform=Linux user_agent=... +``` + +The debug value depends on the path - `&_debug=131` on the Compute API and SAS 9, `&_debug=128` on the Viya web (JES) path with `runAsTask` enabled, which is what the frontend sends there. Either way, switching debug on in the app is enough. + +## Worth knowing + +- The values are supplied by the client. Treat them as diagnostics hints, never as a security boundary. +- `editors/loadfile` is reached through the adapter's multipart file upload, which carries no input tables, so in normal use that service - and the hook it runs - does not receive them. It is on the list for completeness. +- Nothing else pays for the tables: they travel only with the services above. + +Full detail, including the column definitions and the log output, is in the [troubleshooting documentation](https://docs.datacontroller.io/dci-troubleshooting/). + + + + diff --git a/content/feed/support-diagnostics/support-diagnostics.jpeg b/content/feed/support-diagnostics/support-diagnostics.jpeg new file mode 100644 index 0000000..7eaedcf Binary files /dev/null and b/content/feed/support-diagnostics/support-diagnostics.jpeg differ