UNPKG

@datadog/mobile-react-native

Version:

A client-side React Native module to interact with Datadog

142 lines (140 loc) 4.86 kB
/* * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. * This product includes software developed at Datadog (https://www.datadoghq.com/). * Copyright 2016-Present Datadog, Inc. */ import { InternalLog } from '../../../InternalLog'; import { SdkVerbosity } from '../../../SdkVerbosity'; import { DdSdk } from '../../../sdk/DdSdk'; import { getErrorStackTrace } from '../../../utils/errorUtils'; import { DatadogBuffer } from './DatadogBuffer'; const DEFAULT_BUFFER_SIZE = 100; export class BoundedBuffer extends DatadogBuffer { buffer = []; idTable = {}; telemetryBuffer = {}; constructor(bufferSize = DEFAULT_BUFFER_SIZE) { super(); this.bufferSize = bufferSize; } addCallback = callback => { if (this.buffer.length < this.bufferSize) { this.buffer.push({ callback, _type: 'VOID' }); } else { this.logBufferOverflow(); } return new Promise(resolve => resolve(undefined)); }; addCallbackReturningId = callback => { try { const bufferId = this.generateRandomBufferId(); if (this.buffer.length < this.bufferSize) { this.buffer.push({ callback, returnedBufferId: bufferId, _type: 'RETURNING_ID' }); this.idTable[bufferId] = null; } else { this.logBufferOverflow(); } return new Promise(resolve => resolve(bufferId)); } catch (error) { this.logRandomIdGenerationError(error); return new Promise(resolve => resolve('')); } }; addCallbackWithId = (callback, bufferId) => { if (this.idTable[bufferId] !== undefined) { this.buffer.push({ callback, withBufferId: bufferId, _type: 'WITH_ID' }); } else { this.logBufferOverflow(); } return new Promise(resolve => resolve(undefined)); }; drain = async () => { for (let bufferIndex = 0; bufferIndex < this.buffer.length; bufferIndex++) { try { const item = this.buffer[bufferIndex]; if (item._type === 'RETURNING_ID') { try { // Here we want to await the callback result to make sure that it has registered the id returned // by the callback before executing the callback needing this id. // eslint-disable-next-line no-await-in-loop const callbackId = await item.callback(); this.idTable[item.returnedBufferId] = callbackId; } catch (error) { InternalLog.log(`Error running a callback returning an id in Buffer: ${error}`, SdkVerbosity.WARN); } continue; } if (item._type === 'WITH_ID') { const callbackId = this.idTable[item.withBufferId]; // callbackId can be `null` if the callback supposed to return the id errored. In this case, let's ignore the next callback. if (callbackId !== null && callbackId !== undefined) { item.callback(callbackId); delete this.idTable[item.withBufferId]; } else { InternalLog.log(`1 event was not sent as callback id was ${callbackId === null ? 'not set' : 'already unset'}`, SdkVerbosity.WARN); } continue; } item.callback(); } catch (error) { InternalLog.log(`Error while draining Datadog Buffer: ${error}`, SdkVerbosity.WARN); } } this.buffer = []; this.drainTelemetry(); }; logBufferOverflow() { this.addTelemetryEvent('Buffer overflow', '', 'BufferOverflow'); } logRandomIdGenerationError = error => { this.addTelemetryEvent('Could not generate enough random numbers', getErrorStackTrace(error), 'RandomIdGenerationError'); // Not using InternalLog here as it is not yet instantiated console.warn(`[Datadog] Could not generate enough random numbers for RUM buffer. Please check that Math.random is not overwritten. Math.random returns: ${Math.random()}`); }; generateRandomBufferId = () => { let tries = 0; while (tries < 20) { const hash = Math.random().toString(36).slice(2); if (this.idTable[hash] !== undefined) { tries++; } else { return hash; } } throw new Error('Could not generate random Buffer id'); }; addTelemetryEvent = (message, stack, kind) => { if (this.telemetryBuffer[kind]) { this.telemetryBuffer[kind].occurrences++; } else { this.telemetryBuffer[kind] = { message, stack, kind, occurrences: 1 }; } }; drainTelemetry = () => { Object.values(this.telemetryBuffer).forEach(({ message, stack, kind, occurrences }) => { DdSdk.telemetryError(`${message} happened ${occurrences} times.`, stack, kind); }); }; } //# sourceMappingURL=BoundedBuffer.js.map