Skip to content

Commit

Permalink
feat: add browser.name attribute (#130)
Browse files Browse the repository at this point in the history
## Which problem is this PR solving?
Adds a `browser.name` attribute to events

## Short description of the changes
Delegates to [ua-parser-js](https://www.npmjs.com/package/ua-parser-js)
so the list of available browsers comes from there. At its core, this is
just user-agent parsing, with all of the caveats that come with that:
it's fragile, a best guess effort, etc.

ex. I tested with [Arc](https://arc.net) and it's getting parsed as
Chrome; this is expected since Arc doesn't change the User Agent at all.

## How to verify that this has the expected result
Run the app and see `browser.name` attached: 

![image](https://github.com/honeycombio/honeycomb-opentelemetry-web/assets/11722214/3ab5c6a9-6a3e-4104-9609-2e66cf2e5315)
  • Loading branch information
MustafaHaddara authored Apr 29, 2024
1 parent e810125 commit 877f2f1
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ The SDK adds these fields to all telemetry:
| `browser.height` | planned | per-span | [window.innerHeight](https://developer.mozilla.org/en-US/docs/Web/API/Window/innerHeight), the height of the layout viewport in pixels | 287 |
| `browser.width` | planned | per-span | [window.innerWidth](https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth), the height of the layout viewport in pixels | 1720 |
| `browser.brands` | stable | static | [NavigatorUAData: brands](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorUAData/brands) | ["Not_A Brand 8", "Chromium 120", "Google Chrome 120"] |
| `browser.name` | custom | static | Best guess of browser type | "Chrome", "Chromium", "Firefox", "Safari", etc. |
| `browser.version` | custom | static | Version of browser | `109.1` |
| `browser.platform` | stable | static | [NavigatorUAData: platform](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorUAData/platform) | "Windows" |
| `browser.mobile` | stable | static | [NavigatorUAData: mobile](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorUAData/mobile) | true |
| `browser.language` | stable | static | [Navigator: language](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/language) | "fr-FR" |
Expand Down
41 changes: 41 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"license": "Apache-2.0",
"devDependencies": {
"@types/jest": "^29.5.11",
"@types/ua-parser-js": "^0.7.39",
"cypress": "^13.6.4",
"eslint-plugin-import": "^2.29.1",
"jest": "^29.7.0",
Expand All @@ -50,6 +51,7 @@
"axios": "^1.6.7",
"eslint-config-prettier": "^9.1.0",
"prettier": "^3.2.4",
"ua-parser-js": "^1.0.37",
"web-vitals": "^3.5.2"
}
}
14 changes: 14 additions & 0 deletions src/browser-attributes-resource.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Resource } from '@opentelemetry/resources';
import UAParser from 'ua-parser-js';

type ScreenSize = 'small' | 'medium' | 'large' | 'unknown';

Expand All @@ -10,13 +11,26 @@ export const computeScreenSize = (screenWidth: number): ScreenSize => {
return 'unknown';
};

export const computeBrowserName = (userAgent: string) => {
const uaParser = new UAParser(userAgent);
const { name, version } = uaParser.getBrowser();

return {
name: name ?? 'unknown',
version: version ?? 'unknown',
};
};

export function configureBrowserAttributesResource(): Resource {
const { name, version } = computeBrowserName(navigator.userAgent);
return new Resource({
'user_agent.original': navigator.userAgent,
//https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent#mobile_tablet_or_desktop
'browser.mobile': navigator.userAgent.includes('Mobi'),
'browser.touch_screen_enabled': navigator.maxTouchPoints > 0,
'browser.language': navigator.language,
'browser.name': name,
'browser.version': version,
'screen.width': window.screen.width,
'screen.height': window.screen.height,
'screen.size': computeScreenSize(window.screen.width),
Expand Down
69 changes: 69 additions & 0 deletions test/browser-attributes-resource.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
computeBrowserName,
computeScreenSize,
configureBrowserAttributesResource,
} from '../src/browser-attributes-resource';
Expand All @@ -12,6 +13,8 @@ test('it should return a Resource', () => {
test('it should have location attributes', () => {
const resource = configureBrowserAttributesResource();
expect(resource.attributes).toEqual({
'browser.name': 'WebKit',
'browser.version': '537.36',
'browser.language': 'en-US',
'browser.mobile': false,
'browser.touch_screen_enabled': false,
Expand Down Expand Up @@ -39,3 +42,69 @@ describe('compute screen size', () => {
expect(computeScreenSize(1025)).toBe('large');
});
});

describe('compute broweser type', () => {
// sample UAs courtesy of
// https://explore.whatismybrowser.com/useragents/explore/software_name/
// https://useragents.io/explore
const USER_AGENTS = {
'Android Browser': [
'Mozilla/5.0 (Linux; U; Android 4.0.3; de-ch; HTC Sensation Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30',
],
Chrome: [
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36',
'Mozilla/5.0 (X11; CrOS x86_64 8172.45.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.64 Safari/537.36',
'Mozilla/5.0 (Linux; Android 13; TECNO BG6 Build/TP1A.220624.014) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.118 Mobile Safari/537.36',
],
Chromium: [
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/124.0.6329.210 Chrome/124.0.6329.210 Safari/537.36',
],
Edge: [
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0',
'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Mobile Safari/537.36 EdgA/122.0.0.0',
'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 EdgiOS/46.2.5 Mobile/15E148 Safari/605.1.15',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299',
],
Firefox: [
'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0.1',
'Mozilla/5.0 (X11; Linux x86_64; rv:93.0) Gecko/20100101 Firefox/93.0',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:124.0) Gecko/20100101 Firefox/124.0',
'Mozilla/5.0 (Android 14; Mobile; rv:124.0) Gecko/124.0 Firefox/124.0',
'Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/114.1 Mobile/15E148 Safari/605.1.15',
'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:16.0) Gecko/20121011 Firefox/16.0 SeaMonkey/2.13.1 Lightning/1.8',
],
IE: [
'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko',
],
'Mobile Safari': [
'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Mobile/15E148 Safari/604.1',
],
Opera: [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 OPR/107.0.0.0 (Edition std-1)',
'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML like Gecko) Chrome/39.0.2171.65 Safari/537.36 OPR/26.0.1656.24',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 OPR/97.0.0.0',
'Mozilla/5.0 (Windows NT 5.1; U; en) Opera 8.01',
'Opera/9.80 (Windows NT 6.0) Presto/2.12.388 Version/12.14',
],
Safari: [
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/601.3.9 (KHTML, like Gecko) Version/9.0.2 Safari/601.3.9',
'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.71 (KHTML like Gecko) WebVideo/1.0.1.10 Version/7.0 Safari/537.71',
],
unknown: [
'blah blah blah',
'DeathStar/1.0 (X11; Linux x86_64) like StarDestroyer/12.11',
'Hello World',
'Dalvik/2.1.0 (Linux; U; Android 13; SM-A326B Build/TP1A.220624.014)',
],
};

Object.entries(USER_AGENTS).forEach(([type, userAgents]) => {
test(`determines ${type}`, () => {
userAgents.forEach((userAgent) => {
expect(computeBrowserName(userAgent).name).toBe(type);
});
});
});
});

0 comments on commit 877f2f1

Please sign in to comment.