• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

supabase / storage / 25163834703

30 Apr 2026 11:52AM UTC coverage: 71.924% (+0.03%) from 71.891%
25163834703

Pull #1071

github

web-flow
Merge 416c2b114 into d25a84735
Pull Request #1071: fix: iceberg container and acceptance tests

3576 of 5528 branches covered (64.69%)

Branch coverage included in aggregate %.

0 of 2 new or added lines in 1 file covered. (0.0%)

3883 existing lines in 165 files now uncovered.

7465 of 9823 relevant lines covered (76.0%)

392.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.4
/src/http/plugins/log-request.ts
1
import { logSchema, serializeReplyLog, serializeRequestLog } from '@internal/monitoring'
2
import type { FastifyReply, FastifyRequest } from 'fastify'
3
import fastifyPlugin from 'fastify-plugin'
4

5
interface RequestLoggerOptions {
6
  excludeUrls?: string[]
7
}
8

9
type BivariantHandler<Args extends unknown[], Return> = {
10
  bivarianceHack(...args: Args): Return
11
}['bivarianceHack']
12

13
declare module 'http' {
14
  interface IncomingMessage {
15
    executionError?: Error
16
    resources?: string[]
17
  }
18
}
19

20
declare module 'fastify' {
21
  interface FastifyRequest {
22
    executionError?: Error
23
    operation?: { type: string }
24
    resources?: string[]
25
    startTime: number
26
    executionTime?: number
27
  }
28

29
  interface FastifyContextConfig {
30
    operation?: { type: string }
31
    resources?: BivariantHandler<[req: FastifyRequest], string[]>
32
    logMetadata?: BivariantHandler<[req: FastifyRequest], Record<string, unknown>>
33
  }
34
}
35

36
/**
37
 * Request logger plugin
38
 * @param options
39
 */
40
export const logRequest = (options: RequestLoggerOptions) =>
281✔
41
  fastifyPlugin(
42
    async (fastify) => {
43
      fastify.addHook('onRequest', async (req, res) => {
281✔
44
        req.startTime = Date.now()
1,572✔
45

46
        res.raw.once('close', () => {
1,572✔
47
          if (req.raw.aborted) {
1,572!
48
            doRequestLog(req, {
×
49
              excludeUrls: options.excludeUrls,
50
              statusCode: 'ABORTED REQ',
51
              responseTime: (Date.now() - req.startTime) / 1000,
52
            })
53
            return
×
54
          }
55

56
          if (!res.raw.writableFinished) {
1,572✔
57
            doRequestLog(req, {
1,211✔
58
              excludeUrls: options.excludeUrls,
59
              statusCode: 'ABORTED RES',
60
              responseTime: (Date.now() - req.startTime) / 1000,
61
            })
62
          }
63
        })
64
      })
65

66
      /**
67
       * Adds req.resources and req.operation to the request object
68
       */
69
      fastify.addHook('preHandler', async (req) => {
281✔
70
        let resources = req.resources
1,497✔
71

72
        if (resources === undefined) {
1,497!
73
          resources = req.routeOptions.config.resources?.(req)
1,497✔
74
        }
75

76
        if (resources === undefined) {
1,497✔
77
          resources = req.raw.resources
1,420✔
78
        }
79

80
        if (resources === undefined) {
1,497✔
81
          const params = req.params as Record<string, unknown> | undefined
1,420✔
82
          let resourceFromParams = ''
1,420✔
83

84
          if (params) {
1,420!
85
            let first = true
1,420✔
86
            for (const key in params) {
1,420✔
87
              if (!Object.prototype.hasOwnProperty.call(params, key)) {
1,733!
88
                continue
×
89
              }
90

91
              if (!first) {
1,733✔
92
                resourceFromParams += '/'
497✔
93
              }
94

95
              const value = params[key]
1,733✔
96
              resourceFromParams += value == null ? '' : String(value)
1,733!
97
              first = false
1,733✔
98
            }
99
          }
100

101
          resources = resourceFromParams ? [resourceFromParams] : []
1,420✔
102
        }
103

104
        if (resources && resources.length > 0) {
1,497✔
105
          for (let index = 0; index < resources.length; index++) {
1,313✔
106
            const resource = resources[index]
41,348✔
107
            if (!resource.startsWith('/')) {
41,348✔
108
              resources[index] = `/${resource}`
41,347✔
109
            }
110
          }
111
        }
112

113
        req.resources = resources
1,497✔
114
        req.operation = req.routeOptions.config.operation
1,497✔
115

116
        if (req.operation && typeof req.opentelemetry === 'function') {
1,497!
117
          req.opentelemetry()?.span?.setAttribute('http.operation', req.operation.type)
×
118
        }
119
      })
120

121
      fastify.addHook('onSend', async (req, _, payload) => {
281✔
122
        req.executionTime = Date.now() - req.startTime
1,552✔
123
        return payload
1,552✔
124
      })
125

126
      fastify.addHook('onResponse', async (req, reply) => {
281✔
127
        doRequestLog(req, {
1,572✔
128
          reply,
129
          excludeUrls: options.excludeUrls,
130
          statusCode: reply.statusCode,
131
          responseTime: reply.elapsedTime,
132
          executionTime: req.executionTime,
133
        })
134
      })
135
    },
136
    { name: 'log-request' }
137
  )
138

139
interface LogRequestOptions {
140
  reply?: FastifyReply
141
  excludeUrls?: string[]
142
  statusCode: number | 'ABORTED REQ' | 'ABORTED RES'
143
  responseTime: number
144
  executionTime?: number
145
}
146

147
function doRequestLog(req: FastifyRequest, options: LogRequestOptions) {
148
  if (options.excludeUrls?.includes(req.url)) {
2,783!
149
    return
×
150
  }
151

152
  const requestLog = serializeRequestLog(req)
2,783✔
153
  const replyLog = serializeReplyLog(options.reply)
2,783✔
154
  const rMeth = requestLog.method
2,783✔
155
  const rUrl = requestLog.url
2,783✔
156
  const uAgent = req.headers['user-agent']
2,783✔
157
  const rId = req.id
2,783✔
158
  const cIP = req.ip
2,783✔
159
  const statusCode = options.statusCode
2,783✔
160
  const error = req.raw.executionError || req.executionError
2,783✔
161
  const tenantId = req.tenantId
2,783✔
162

163
  let reqMetadata: Record<string, unknown> = {}
2,783✔
164

165
  if (req.routeOptions.config.logMetadata) {
2,783✔
UNCOV
166
    try {
380✔
UNCOV
167
      reqMetadata = req.routeOptions.config.logMetadata(req)
380✔
168

UNCOV
169
      if (reqMetadata) {
380!
UNCOV
170
        try {
380✔
UNCOV
171
          if (typeof req.opentelemetry === 'function') {
380!
172
            req.opentelemetry()?.span?.setAttribute('http.metadata', JSON.stringify(reqMetadata))
×
173
          }
174
        } catch (e) {
175
          // do nothing
176
          logSchema.warning(req.log, 'Failed to serialize log metadata', {
×
177
            type: 'otel',
178
            tenantId,
179
            project: tenantId,
180
            reqId: rId,
181
            sbReqId: req.sbReqId,
182
            error: e,
183
          })
184
        }
185
      }
186
    } catch (e) {
187
      logSchema.error(req.log, 'Failed to get log metadata', {
×
188
        type: 'request',
189
        tenantId,
190
        project: tenantId,
191
        reqId: rId,
192
        sbReqId: req.sbReqId,
193
        error: e,
194
      })
195
    }
196
  }
197

198
  const buildLogMessage = `${tenantId} | ${rMeth} | ${statusCode} | ${cIP} | ${rId} | ${rUrl} | ${uAgent}`
2,783✔
199

200
  logSchema.request(req.log, buildLogMessage, {
2,783✔
201
    type: 'request',
202
    tenantId,
203
    project: tenantId,
204
    reqId: rId,
205
    sbReqId: req.sbReqId,
206
    req: requestLog,
207
    reqMetadata,
208
    res: replyLog,
209
    responseTime: options.responseTime,
210
    executionTime: options.executionTime,
211
    error,
212
    owner: req.owner,
213
    role: req.jwtPayload?.role,
214
    resources: req.resources,
215
    operation: req.operation?.type ?? req.routeOptions.config.operation?.type,
3,708✔
216
    serverTimes: req.serverTimings,
217
  })
218
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc