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

supabase / storage / 24199330927

09 Apr 2026 03:43PM UTC coverage: 80.863% (+0.02%) from 80.843%
24199330927

Pull #922

github

web-flow
Merge 08a9d280c into 41cfe7541
Pull Request #922: fix: no any rule

3199 of 4186 branches covered (76.42%)

Branch coverage included in aggregate %.

513 of 614 new or added lines in 52 files covered. (83.55%)

1 existing line in 1 file now uncovered.

30549 of 37549 relevant lines covered (81.36%)

324.38 hits per line

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

85.43
/src/http/plugins/log-request.ts
1
import { logger, logSchema, redactQueryParamFromRequest } from '@internal/monitoring'
1✔
2
import { RouteGenericInterface } from 'fastify'
1✔
3
import { FastifyReply } from 'fastify/types/reply'
1✔
4
import { FastifyRequest } from 'fastify/types/request'
1✔
5
import fastifyPlugin from 'fastify-plugin'
1✔
6

1✔
7
interface RequestLoggerOptions {
1✔
8
  excludeUrls?: string[]
1✔
9
}
1✔
10

1✔
11
type RawRequestMetadata = FastifyRequest['raw'] & {
1✔
12
  executionError?: Error
1✔
13
  resources?: string[]
1✔
14
}
1✔
15

1✔
16
declare module 'fastify' {
1✔
17
  interface FastifyRequest {
1✔
18
    executionError?: Error
1✔
19
    operation?: { type: string }
1✔
20
    resources?: string[]
1✔
21
    startTime: number
1✔
22
    executionTime?: number
1✔
23
  }
1✔
24

1✔
25
  interface FastifyContextConfig {
1✔
26
    operation?: { type: string }
1✔
27
    resources?(req: FastifyRequest<RouteGenericInterface>): string[]
1✔
28
    logMetadata?(req: FastifyRequest<RouteGenericInterface>): Record<string, unknown>
1✔
29
  }
1✔
30
}
1✔
31

1✔
32
/**
1✔
33
 * Request logger plugin
1✔
34
 * @param options
1✔
35
 */
1✔
36
export const logRequest = (options: RequestLoggerOptions) =>
1✔
37
  fastifyPlugin(
276✔
38
    async (fastify) => {
276✔
39
      fastify.addHook('onRequest', async (req, res) => {
268✔
40
        req.startTime = Date.now()
1,508✔
41

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

1,508✔
52
          if (!res.raw.writableFinished) {
1,508✔
53
            doRequestLog(req, {
1,164✔
54
              excludeUrls: options.excludeUrls,
1,164✔
55
              statusCode: 'ABORTED RES',
1,164✔
56
              responseTime: (Date.now() - req.startTime) / 1000,
1,164✔
57
            })
1,164✔
58
          }
1,164✔
59
        })
1,508✔
60
      })
268✔
61

268✔
62
      /**
268✔
63
       * Adds req.resources and req.operation to the request object
268✔
64
       */
268✔
65
      fastify.addHook('preHandler', async (req) => {
268✔
66
        let resources = req.resources
1,435✔
67

1,435✔
68
        if (resources === undefined) {
1,435✔
69
          resources = req.routeOptions.config.resources?.(req)
1,434✔
70
        }
1,434✔
71

1,435✔
72
        if (resources === undefined) {
1,435✔
73
          resources = getRawRequest(req).resources
1,370✔
74
        }
1,370✔
75

1,435✔
76
        if (resources === undefined) {
1,435✔
77
          const resourceFromParams = getResourceFromParams(req.params)
1,370✔
78
          resources = resourceFromParams ? [resourceFromParams] : []
1,370✔
79
        }
1,370✔
80

1,435✔
81
        if (resources && resources.length > 0) {
1,435✔
82
          for (let index = 0; index < resources.length; index++) {
1,258✔
83
            const resource = resources[index]
41,293✔
84
            if (!resource.startsWith('/')) {
41,293✔
85
              resources[index] = `/${resource}`
41,291✔
86
            }
41,291✔
87
          }
41,293✔
88
        }
1,258✔
89

1,435✔
90
        req.resources = resources
1,435✔
91
        req.operation = req.routeOptions.config.operation
1,435✔
92

1,435✔
93
        if (req.operation && typeof req.opentelemetry === 'function') {
1,435!
94
          req.opentelemetry()?.span?.setAttribute('http.operation', req.operation.type)
×
95
        }
×
96
      })
268✔
97

268✔
98
      fastify.addHook('onSend', async (req, _, payload) => {
268✔
99
        req.executionTime = Date.now() - req.startTime
1,488✔
100
        return payload
1,488✔
101
      })
268✔
102

268✔
103
      fastify.addHook('onResponse', async (req, reply) => {
268✔
104
        doRequestLog(req, {
1,508✔
105
          reply,
1,508✔
106
          excludeUrls: options.excludeUrls,
1,508✔
107
          statusCode: reply.statusCode,
1,508✔
108
          responseTime: reply.elapsedTime,
1,508✔
109
          executionTime: req.executionTime,
1,508✔
110
        })
1,508✔
111
      })
268✔
112
    },
268✔
113
    { name: 'log-request' }
276✔
114
  )
1✔
115

1✔
116
interface LogRequestOptions {
1✔
117
  reply?: FastifyReply
1✔
118
  excludeUrls?: string[]
1✔
119
  statusCode: number | 'ABORTED REQ' | 'ABORTED RES'
1✔
120
  responseTime: number
1✔
121
  executionTime?: number
1✔
122
}
1✔
123

1✔
124
function doRequestLog(req: FastifyRequest, options: LogRequestOptions) {
2,672✔
125
  if (options.excludeUrls?.includes(req.url)) {
2,672!
126
    return
×
127
  }
×
128

2,672✔
129
  const rMeth = req.method
2,672✔
130
  const rUrl = redactQueryParamFromRequest(req, [
2,672✔
131
    'token',
2,672✔
132
    'X-Amz-Credential',
2,672✔
133
    'X-Amz-Signature',
2,672✔
134
    'X-Amz-Security-Token',
2,672✔
135
  ])
2,672✔
136
  const uAgent = req.headers['user-agent']
2,672✔
137
  const rId = req.id
2,672✔
138
  const cIP = req.ip
2,672✔
139
  const statusCode = options.statusCode
2,672✔
140
  const error = getRawRequest(req).executionError || req.executionError
2,672✔
141
  const tenantId = req.tenantId
2,672✔
142

2,672✔
143
  let reqMetadata: Record<string, unknown> = {}
2,672✔
144

2,672✔
145
  if (req.routeOptions.config.logMetadata) {
2,672✔
146
    try {
380✔
147
      reqMetadata = req.routeOptions.config.logMetadata(req)
380✔
148

380✔
149
      if (reqMetadata) {
380✔
150
        try {
380✔
151
          if (typeof req.opentelemetry === 'function') {
380!
152
            req.opentelemetry()?.span?.setAttribute('http.metadata', JSON.stringify(reqMetadata))
×
153
          }
×
154
        } catch (e) {
380!
155
          // do nothing
×
156
          logSchema.warning(logger, 'Failed to serialize log metadata', {
×
157
            type: 'otel',
×
158
            error: e,
×
159
          })
×
160
        }
×
161
      }
380✔
162
    } catch (e) {
380!
163
      logSchema.error(logger, 'Failed to get log metadata', {
×
164
        type: 'request',
×
165
        error: e,
×
166
      })
×
167
    }
×
168
  }
380✔
169

2,672✔
170
  const buildLogMessage = `${tenantId} | ${rMeth} | ${statusCode} | ${cIP} | ${rId} | ${rUrl} | ${uAgent}`
2,672✔
171

2,672✔
172
  logSchema.request(req.log, buildLogMessage, {
2,672✔
173
    type: 'request',
2,672✔
174
    req,
2,672✔
175
    reqMetadata,
2,672✔
176
    res: options.reply,
2,672✔
177
    responseTime: options.responseTime,
2,672✔
178
    executionTime: options.executionTime,
2,672✔
179
    error,
2,672✔
180
    owner: req.owner,
2,672✔
181
    role: req.jwtPayload?.role,
2,672✔
182
    resources: req.resources,
2,672✔
183
    operation: req.operation?.type ?? req.routeOptions.config.operation?.type,
2,672✔
184
    serverTimes: req.serverTimings,
2,672✔
185
  })
2,672✔
186
}
2,672✔
187

1✔
188
function getRawRequest(req: FastifyRequest): RawRequestMetadata {
4,042✔
189
  return req.raw as RawRequestMetadata
4,042✔
190
}
4,042✔
191

1✔
192
function getResourceFromParams(params: unknown): string {
1,370✔
193
  if (!params || typeof params !== 'object') {
1,370!
NEW
194
    return ''
×
NEW
195
  }
×
196

1,370✔
197
  let resource = ''
1,370✔
198
  let first = true
1,370✔
199

1,370✔
200
  for (const key in params) {
1,370✔
201
    if (!Object.prototype.hasOwnProperty.call(params, key)) {
1,671!
NEW
202
      continue
×
NEW
203
    }
×
204

1,671✔
205
    if (!first) {
1,671✔
206
      resource += '/'
478✔
207
    }
478✔
208

1,671✔
209
    const value = (params as Record<string, unknown>)[key]
1,671✔
210
    resource += value == null ? '' : String(value)
1,671!
211
    first = false
1,671✔
212
  }
1,671✔
213

1,370✔
214
  return resource
1,370✔
215
}
1,370✔
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