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

supabase / storage / 25337286757

04 May 2026 06:54PM UTC coverage: 35.301% (-37.9%) from 73.177%
25337286757

Pull #1080

github

web-flow
Merge 7b2df3775 into 6034b72fb
Pull Request #1080: fix: defs and recursion for vectors api docs

1760 of 5582 branches covered (31.53%)

Branch coverage included in aggregate %.

7 of 16 new or added lines in 1 file covered. (43.75%)

3834 existing lines in 164 files now uncovered.

3641 of 9718 relevant lines covered (37.47%)

12.09 hits per line

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

75.23
/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) =>
8✔
41
  fastifyPlugin(
42
    async (fastify) => {
43
      fastify.addHook('onRequest', async (req, res) => {
8✔
44
        req.startTime = Date.now()
8✔
45

46
        res.raw.once('close', () => {
8✔
47
          if (req.raw.aborted) {
8!
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) {
8!
57
            doRequestLog(req, {
8✔
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) => {
8✔
70
        let resources = req.resources
7✔
71

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

76
        if (resources === undefined) {
7✔
77
          resources = req.raw.resources
6✔
78
        }
79

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

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

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

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

101
          resources = resourceFromParams ? [resourceFromParams] : []
6✔
102
        }
103

104
        if (resources && resources.length > 0) {
7✔
105
          for (let index = 0; index < resources.length; index++) {
3✔
106
            const resource = resources[index]
4✔
107
            if (!resource.startsWith('/')) {
4✔
108
              resources[index] = `/${resource}`
3✔
109
            }
110
          }
111
        }
112

113
        req.resources = resources
7✔
114
        req.operation = req.routeOptions.config.operation
7✔
115

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

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

126
      fastify.addHook('onResponse', async (req, reply) => {
8✔
127
        doRequestLog(req, {
8✔
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)) {
16!
149
    return
×
150
  }
151

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

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

165
  if (req.routeOptions.config.logMetadata) {
16!
UNCOV
166
    try {
×
UNCOV
167
      reqMetadata = req.routeOptions.config.logMetadata(req)
×
168

UNCOV
169
      if (reqMetadata) {
×
UNCOV
170
        try {
×
UNCOV
171
          if (typeof req.opentelemetry === 'function') {
×
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}`
16✔
199

200
  logSchema.request(req.log, buildLogMessage, {
16✔
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,
32✔
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