@matrix500mg-plugins/angular
v1.0.4
Published
Framework-agnostic OpenTelemetry frontend SDK — Grafana Tempo + Loki
Readme
@matrix500mg-plugins/angular
Frontend observability SDK for DMI apps — OpenTelemetry traces to Grafana Tempo, logs to Loki, Web Vitals, and cross-project journey linking.
Framework-agnostic core; used from Angular via the standard 4-file kit
(matrix500-config.ts, -init.ts, -tracking.service.ts, -http.interceptor.ts).
⚠️ Upgrading to 1.0.4 — read this first
1.0.4 removes raw mobile numbers from all telemetry. If you upgrade without
setting piiSalt, nothing crashes — but cross-project journey linking silently
breaks, which is the worst kind of failure. Two things to do:
1. Set piiSalt, identically in every project
export const OBS_CONFIG = {
// ...
piiSalt: (window as any).__OBS_PII_SALT__ ?? 'dmi-matrix500-2026',
};Every app that takes part in a handoff (gpay → kyc, phonepe → kyc) must use
the same salt. A different salt means a different user.hash, which means the
two halves of the journey never join up. Inject it at build time; don't commit
the production value.
The backend needs the same value as APM_PII_SALT in .env.
2. Update anything that queried user.mobile
user.mobile and user.email are no longer emitted on spans or log lines.
user.hash replaces them:
# before
{ span.user.mobile = "9876543210" }
# after
{ span.user.hash = "b151eb9af95ccacbc72657b06c66322f" }To go from a mobile number to its hash, call the backend SDK's
POST /V1/apm/user-hash (admin-token protected). Don't compute it by hand.
Why: the trace id used to be the mobile number hex-encoded, which is reversible in two lines of JavaScript. Every span also carried the number in plaintext. For an NBFC that is not acceptable at rest in Tempo or Loki.
Also changed in 1.0.4
- Trace ids rotate daily. Previously one mobile mapped to one trace id
forever, so a returning user's trace grew without bound until Tempo dropped
it. Ids are still deterministic (handoffs still land in one trace) but are now
bucketed per day. Follow a user across days via
user.hash. - Spans survive a failed export. They used to be discarded when the endpoint was down or the circuit breaker was open. They are now re-queued.
maxExportBatchSizeis honoured. It was declared but never read; the whole pending queue went out in one request.- Error storms are rate-limited. An error inside a render loop used to emit a span and a Loki line per occurrence.
- INP is collected.
interaction_to_next_paint_mson page-load spans. traceparentcarries a real span id. The id it sent before was never exported, so backend spans pointed at a parent Tempo had never seen and rendered as detached, badly ordered roots.
Install
npm install @matrix500mg-plugins/angularQuick start
// main.ts — before bootstrap, so early spans and bootstrap errors are captured
import { initializeObservability } from '@matrix500mg-plugins/angular';
initializeObservability({
serviceName: 'dmi-frontend',
environment: 'production',
otlpEndpoint: 'https://apmuat.dmifinance.in/v1/traces',
lokiEndpoint: 'https://apmuat.dmifinance.in/loki/api/v1/push',
piiSalt: '...', // same in every project
corsUrls: ['https://dmikyc.dmifinance.in'], // traceparent goes only here
customAttributes: { 'project.name': 'dmi-kyc-FE' },
});Post-login, attach the user:
import { startUserSession } from '@matrix500mg-plugins/angular';
startUserSession({ mobile: '9876543210' }); // hashed immediately, never stored rawConfig
| Key | Default | Notes |
|---|---|---|
| serviceName | — | Constant across DMI apps |
| environment | — | production / development |
| otlpEndpoint | — | Tempo (or the OTel Collector) |
| lokiEndpoint | — | Full push URL, /loki/api/v1/push |
| piiSalt | matrix500-default-salt | Set this. Must match across projects |
| corsUrls | [] | Origins that receive traceparent |
| customAttributes | {} | Must include project.name |
| maxExportBatchSize | 50 | Spans per export request |
| scheduledDelayMillis | 5000 | Batch flush interval |
| propagateTraceHeaders | true | Needs corsUrls to do anything |
| enableTTFI / enablePageTracking / enableApiTracking / enableRouterTracking / enableGlobalErrors / enablePerformanceMetrics | true | Feature flags |
What lands in Tempo
page_load, js_error, journey_step, cta_click, cta_response,
form_complete, field_input, field_error, screen_buffering, plus one span
per API call from the interceptor.
Common attributes on every span: user.hash, session.id, page.route,
service.name, deployment.environment, browser metadata, and whatever you put
in customAttributes.
Notes
piiSalt makes the hash one-way, but a 10-digit mobile has only 10^10 possible
values — anyone holding the salt can brute-force it. The salt ships in a browser
bundle, so treat this as removing plaintext PII at rest, not as protection
against a determined attacker. Server-side pseudonymisation is the stronger
answer if that threat matters.
Build
npm install
npm run build # rollup -> dist/prepublishOnly runs the build, so npm publish always ships a fresh dist/.
