Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancements to Shaka Error Handling #12

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# CHANGELOG

## [0.4.0] - 2024/10/07
### New
- Introduced a mapper to transform Shaka errors into a more organized format for New Relic.

### Update
- Attached the error `EventListener` to the player instead of its tag.
- Fixed the Webpack environment flag in dev tools.

## [0.3.0] - 2024/10/07
### Update
- Upgraded Shaka Player version `4.11.2`.
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

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

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"name": "newrelic-video-shaka",
"version": "0.3.0",
"version": "0.4.0",
"description": "New relic tracker for shaka player",
"main": "src/index.js",
"scripts": {
"test": "jest --coverage",
"build": "webpack -p",
"build": "webpack --mode production",
"build:dev": "webpack --mode development",
"watch": "webpack -p --progress --color --watch",
"watch:dev": "webpack --progress --color --watch",
"watch": "webpack --mode production --progress --color --watch",
"watch:dev": "webpack --mode development --progress --color --watch",
"prezip": "npm run build",
"zip": "zip -P newrelic -x '*.DS_Store' -r shaka.zip dist samples README.md CHANGELOG.md EULA.md",
"clean": "rm -rf dist *.zip",
Expand Down
4 changes: 2 additions & 2 deletions src/__test__/tracker.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ describe("registerListeners", () => {
"seeking",
expect.any(Function)
);
expect(shakaTracker.tag.addEventListener).toHaveBeenCalledWith(
expect(shakaTracker.player.addEventListener).toHaveBeenCalledWith(
"error",
expect.any(Function)
);
Expand Down Expand Up @@ -363,7 +363,7 @@ describe("unregisterListeners", () => {
"seeking",
expect.any(Function)
);
expect(shakaTracker.tag.addEventListener).toHaveBeenCalledWith(
expect(shakaTracker.player.addEventListener).toHaveBeenCalledWith(
"error",
expect.any(Function)
);
Expand Down
85 changes: 85 additions & 0 deletions src/__test__/utils/mapper.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import ShakaToNewRelicMapper from '../../utils/mapper';

describe('ShakaToNewRelicMapper', () => {
describe('mapErrorAttributes', () => {
it('should return the mapped error attributes', () => {
const attributes = {
code: 1001,
platformCode: 'PLATFORM_ERROR',
message: 'An error occurred',
stack: 'Error stack trace',
severity: 2,
extraAttribute: 'extraValue'
};

const result = ShakaToNewRelicMapper.mapErrorAttributes(attributes);

expect(result).toEqual({
errorCode: 1001,
errorPlatformCode: 'PLATFORM_ERROR',
errorMessage: 'An error occurred',
errorStackTrace: 'Error stack trace',
errorSeverity: 'CRITICAL',
extraAttribute: 'extraValue'
});
});

it('should truncate the stack trace if it exceeds the maximum length', () => {
const longStackTrace = 'a'.repeat(5000);
const attributes = {
stack: longStackTrace
};

const result = ShakaToNewRelicMapper.mapErrorAttributes(attributes);

expect(result.errorStackTrace.length).toBe(4096);
});

it('should return the original attributes if input is not an object', () => {
const attributes = 'not an object';

const result = ShakaToNewRelicMapper.mapErrorAttributes(attributes);

expect(result).toBe(attributes);
});

it('should handle undefined stack trace gracefully', () => {
const attributes = {
code: 1001,
platformCode: 'PLATFORM_ERROR',
message: 'An error occurred',
severity: 2
};

const result = ShakaToNewRelicMapper.mapErrorAttributes(attributes);

expect(result).toEqual({
errorCode: 1001,
errorPlatformCode: 'PLATFORM_ERROR',
errorMessage: 'An error occurred',
errorStackTrace: undefined,
errorSeverity: 'CRITICAL'
});
});

it('should map severity correctly', () => {
const attributes = {
severity: 1
};

const result = ShakaToNewRelicMapper.mapErrorAttributes(attributes);

expect(result.errorSeverity).toBe('RECOVERABLE');
});

it('should retain unknown severity values', () => {
const attributes = {
severity: 3
};

const result = ShakaToNewRelicMapper.mapErrorAttributes(attributes);

expect(result.errorSeverity).toBe(3);
});
});
});
7 changes: 4 additions & 3 deletions src/tracker.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as nrvideo from "newrelic-video-core";
import { version } from "../package.json";
import ShakaToNewRelicMapper from "./utils/mapper";

export default class ShakaTracker extends nrvideo.VideoTracker {
setPlayer(player, tag) {
Expand Down Expand Up @@ -91,8 +92,8 @@ export default class ShakaTracker extends nrvideo.VideoTracker {
this.tag.addEventListener("playing", this.onPlaying.bind(this));
this.tag.addEventListener("seeking", this.onSeeking.bind(this));
this.tag.addEventListener("seeked", this.onSeeked.bind(this));
this.tag.addEventListener("error", this.onError.bind(this));

this.player.addEventListener("error", this.onError.bind(this));
this.player.addEventListener("buffering", this.onBuffering.bind(this));
this.player.addEventListener("adaptation", this.onAdaptation.bind(this));
}
Expand All @@ -104,9 +105,9 @@ export default class ShakaTracker extends nrvideo.VideoTracker {
this.tag.removeEventListener("pause", this.onPause);
this.tag.removeEventListener("seeking", this.onSeeking);
this.tag.removeEventListener("seeked", this.onSeeked);
this.tag.removeEventListener("error", this.onError);
this.tag.removeEventListener("ended", this.onEnded);

this.player.removeEventListener("error", this.onError);
this.player.removeEventListener("loadstart", this.onDownload);
this.player.removeEventListener("loadedmetadata", this.onDownload);
}
Expand Down Expand Up @@ -149,7 +150,7 @@ export default class ShakaTracker extends nrvideo.VideoTracker {
}

onError(e) {
this.sendError(e.detail);
this.sendError(ShakaToNewRelicMapper.mapErrorAttributes(e.detail));
}

onEnded() {
Expand Down
32 changes: 32 additions & 0 deletions src/utils/mapper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const NR_ERROR_CODE = 'errorCode';
const NR_ERROR_PLATFORM_CODE = 'errorPlatformCode';
const NR_ERROR_MESSAGE = 'errorMessage';
const NR_ERROR_STACK_TRACE = 'errorStackTrace';
const NR_ERROR_SEVERITY = 'errorSeverity';
const NR_MAX_NUMBER_OF_CHARACTERS_FOR_STRING_ATTRIBUTE = 4096;

const SHAKA_SEVERITY_MAP = {
1: 'RECOVERABLE',
2: 'CRITICAL'
};

export default class ShakaToNewRelicMapper {
static mapErrorAttributes(attributes) {
if (!attributes || typeof attributes !== 'object') return attributes;

const { code, platformCode, message, stack, severity, ...remainingAttributes } = attributes;

const stackTrace = stack && typeof stack === 'string' ? stack.substring(0, NR_MAX_NUMBER_OF_CHARACTERS_FOR_STRING_ATTRIBUTE) : undefined;
const errorSeverity = SHAKA_SEVERITY_MAP[severity] || severity;

return {
[NR_ERROR_CODE]: code,
[NR_ERROR_PLATFORM_CODE]: platformCode,
[NR_ERROR_MESSAGE]: message,
[NR_ERROR_STACK_TRACE]: stackTrace,
[NR_ERROR_SEVERITY]: errorSeverity,
...remainingAttributes
};
}
}