Skip to content

Commit

Permalink
feat: dont report responses served from browser cache
Browse files Browse the repository at this point in the history
  • Loading branch information
guanzo committed Sep 28, 2023
1 parent 5d61f9d commit 52163bc
Showing 1 changed file with 96 additions and 40 deletions.
136 changes: 96 additions & 40 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,17 @@ class Saturn {
this.opts = Object.assign({}, {
clientId: randomUUID(),
cdnURL: 'saturn.ms',
logURL: 'https://twb3qukm2i654i3tnvx36char40aymqq.lambda-url.us-west-2.on.aws/',
connectTimeout: 5_000,
downloadTimeout: 0
}, opts)

this.reportingLogs = process?.env?.NODE_ENV !== 'development'
this.logs = []
this.reportingLogs = process?.env?.NODE_ENV !== 'development'
this.hasPerformanceAPI = typeof window !== 'undefined' && window?.performance
if (this.reportingLogs && this.hasPerformanceAPI) {
this._monitorPerformanceBuffer()
}
}

/**
Expand All @@ -43,9 +48,7 @@ class Saturn {

const log = {
url,
range: null,
startTime: new Date(),
numBytesSent: 0
startTime: new Date()
}

const controller = new AbortController()
Expand Down Expand Up @@ -80,8 +83,6 @@ class Saturn {
this._finalizeLog(log)

throw err
} finally {
this._addPerformanceAPIMetrics(log)
}

return { res, log }
Expand All @@ -100,6 +101,8 @@ class Saturn {
const { res, log } = await this.fetchCID(cidPath, opts)

async function * metricsIterable (itr) {
log.numBytesSent = 0

for await (const chunk of itr) {
log.numBytesSent += chunk.length
yield chunk
Expand Down Expand Up @@ -177,48 +180,101 @@ class Saturn {
}

async _reportLogs () {
if (this.logs.length) {
await fetch(
'https://twb3qukm2i654i3tnvx36char40aymqq.lambda-url.us-west-2.on.aws/',
{
method: 'POST',
body: JSON.stringify({
bandwidthLogs: this.logs
})
}
)
this.logs = []
if (!this.logs.length) {
return
}

let bandwidthLogs = this.logs
if (this.hasPerformanceAPI) {
bandwidthLogs = this._matchLogsWithPerformanceMetrics(bandwidthLogs)
}

await fetch(
this.opts.logURL,
{
method: 'POST',
body: JSON.stringify({ bandwidthLogs, logSender: this.opts.logSender })
}
)

this.logs = []
this._clearPerformanceBuffer()
}

/**
*
* @param {Array<object>} logs
*/
_matchLogsWithPerformanceMetrics (logs) {
const logsToReport = []

for (const log of logs) {
const metrics = this._getPerformanceMetricsForLog(log)

if (!metrics.isFromBrowserCache) {
delete metrics.isFromBrowserCache
Object.assign(log, metrics)
logsToReport.push(log)
}
}

return logsToReport
}

/**
*
* @param {object} log
* @returns {object}
*/
_addPerformanceAPIMetrics (log) {
if (typeof window !== 'undefined' && window?.performance) {
const entry = performance
.getEntriesByType('resource')
.find((r) => r.name === log.url.href)
if (entry) {
const dnsStart = entry.domainLookupStart
const dnsEnd = entry.domainLookupEnd
const hasData = dnsEnd > 0 && dnsStart > 0
if (hasData) {
log.dnsTimeMs = Math.round(dnsEnd - dnsStart)
log.ttfbAfterDnsMs = Math.round(
entry.responseStart - entry.requestStart
)
}

if (log.httpProtocol === null && entry.nextHopProtocol) {
log.httpProtocol = entry.nextHopProtocol
}
// else response didn't have Timing-Allow-Origin: *
//
// if both dnsStart and dnsEnd are > 0 but have the same value,
// its a dns cache hit.
_getPerformanceMetricsForLog (log) {
const metrics = {}

const entry = performance
.getEntriesByType('resource')
.find((r) => r.name === log.url.href)

if (entry) {
const dnsStart = entry.domainLookupStart
const dnsEnd = entry.domainLookupEnd
const hasDnsMetrics = dnsEnd > 0 && dnsStart > 0

if (hasDnsMetrics) {
metrics.dnsTimeMs = Math.round(dnsEnd - dnsStart)
metrics.ttfbAfterDnsMs = Math.round(
entry.responseStart - entry.requestStart
)
}

if (entry.nextHopProtocol) {
metrics.httpProtocol = entry.nextHopProtocol
}

metrics.isFromBrowserCache = (
entry.deliveryType === 'cache' ||
(log.httpStatusCode && entry.transferSize === 0)
)
}

return metrics
}

_monitorPerformanceBuffer () {
// Using static method prevents multiple unnecessary listeners.
performance.addEventListener('resourcetimingbufferfull', Saturn._setResourceBufferSize)
}

static _setResourceBufferSize () {
const increment = 250
const maxSize = 1000
const size = performance.getEntriesByType('resource').length
const newSize = Math.min(size + increment, maxSize)

performance.setResourceTimingBufferSize(newSize)
}

_clearPerformanceBuffer () {
if (this.hasPerformanceAPI) {
performance.clearResourceTimings()
}
}
}
Expand Down

0 comments on commit 52163bc

Please sign in to comment.