feed: add a support diagnostics post (browser_info, browser_url_vars) #24
@@ -0,0 +1,148 @@
|
||||
---
|
||||
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. A URL parameter by name:
|
||||
|
||||
```sas
|
||||
%let labels=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';
|
||||
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/).
|
||||
|
||||
<!--
|
||||
Source LinkedIn post:
|
||||
|
||||
A support ticket starts with questions. Which browser? Which timezone? Which build? What was in the URL?
|
||||
|
||||
Data Controller now answers them itself.
|
||||
|
||||
Two tables travel with the startup service, and with every service that runs your own code:
|
||||
|
||||
→ browser_info - one row: browser and version, platform, timezone and UTC offset, locale, the DC and adapter builds, the page URL and the referrer
|
||||
|
||||
→ browser_url_vars - one row per URL parameter, name and value, read straight into a macro variable
|
||||
|
||||
Both land in the job log when debug is on, so a ticket can be diagnosed from the log instead of a round trip. Both are readable from a hook script - %include shares the service's WORK library, so a hook can branch on the user's timezone, or pick up a parameter from the URL.
|
||||
|
||||
They are client supplied values: diagnostics hints, not a security boundary. Guard with %sysfunc(exist()) - a service called directly, or an older frontend, sends nothing.
|
||||
|
||||
✅ Full detail in the Data Controller documentation - link in the comments.
|
||||
|
||||
#sas #sasviya #datagovernance #datacapture #sasjs
|
||||
-->
|
||||
|
||||
<!-- Image prompt:
|
||||
Generate a 16:9 landscape illustration for a B2B data-governance blog cover, 1200x627.
|
||||
|
||||
Style: flat vector illustration, dark slate background (#314351) with a faint evenly spaced dot grid, brand green accent (#90c445), lighter slate panels (#2e4252), soft diffused shadows, subtle depth.
|
||||
|
||||
Scene: two rounded panels side by side, each with a header bar in brand green and four rows of rounded cells. The left panel carries short uniform value blocks (the browser context); the right panel carries name-and-value pairs, drawn as a narrow block beside a wider one (the URL parameters), with a single row in the left panel highlighted in green. Between and below the panels a thin vertical connector line runs down to a wide, flat log strip of alternating short green rules on a lighter slate panel, suggesting the tables being written to a job log.
|
||||
|
||||
Minimal text, no letters, no numbers, no logos, no watermark. Keep the subject inside the central square so a 1:1 crop is safe; the outer left and right thirds may be croppable background only.
|
||||
|
||||
Output: save as ./support-diagnostics.jpeg at 1200x627 (matching the other feed covers, and doubling as the LinkedIn share card). Do not also embed the image in the markdown body.
|
||||
-->
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
Reference in New Issue
Block a user