log speed #886
Massimo Melina committed
Feb 10, 2025 at 14:09 UTC
9c5b42562dfc47d21e4325b95c9f7468f67ce36a
3 files changed
+15
-8
admin/src/LogsPage.ts
+4
-4
@@ -6,7 +6,7 @@ import { API_URL, apiCall, useApi, useApiList } from './api'
6
import { DataTable, DataTableProps } from './DataTable'
7
import {
8
CFG, Dict, formatBytes, HTTP_UNAUTHORIZED, newDialog, prefix, shortenAgent, splitAt, tryJson, md,
9
- typedKeys, NBSP, _dbg, mapFilter, safeDecodeURIComponent, stringAfter, onlyTruthy, formatTimestamp
9
+ typedKeys, _dbg, mapFilter, safeDecodeURIComponent, stringAfter, onlyTruthy, formatTimestamp, formatSpeed
10
} from '@hfs/shared'
11
import {
12
NetmaskField, Flex, IconBtn, useBreakpoint, usePauseButton, useToggleButton, WildcardsSupported, Country,
@@ -283,7 +283,7 @@ export function LogFile({ file, footerSide, hidden, limit, filter, ...rest }: Lo
283
{
284
field: 'notes',
285
headerName: "Notes",
286
- width: 105, // https://github.com/rejetto/hfs/discussions/388
286
+ width: 110,
287
hideUnder: 'sm',
288
cellClassName: 'wrap',
289
renderCell: ({ value }) => value && md(value),
@@ -323,8 +323,8 @@ export function LogFile({ file, footerSide, hidden, limit, filter, ...rest }: Lo
323
const upload = row.method === 'PUT' || extra?.ul
324
if (upload)
325
row.length = extra?.size
326
- row.notes = extra?.dl ? "fully downloaded" // 'dl' here is not the '?dl' of the url, and has a different meaning
327
- : upload ? `${partial ? "partial " : ""} upload`
326
+ row.notes = extra?.dl ? "full download " + (extra.speed ? formatSpeed(extra.speed, { sep: ' ' }) : '') // 'dl' here is not the '?dl' of the url, and has a different meaning
327
+ : upload ? `${partial ? "partial " : ""} upload ${extra.speed ? formatSpeed(extra.speed, { sep: ' ' }) : 0}`
328
: row.status === HTTP_UNAUTHORIZED && row.uri?.startsWith(API_URL + 'loginSrp') ? "login failed" + prefix(':\n', extra?.u)
329
: _.map(extra?.params, (v, k) => `${k}: ${v}\n`).join('') + (row.notes || '')
330
}
src/cross.ts
+1
-1
@@ -103,7 +103,7 @@ export function formatBytes(n: number, { post='B', k=0, digits=NaN, sep=' ' }={}
103
return nAsString + sep + (MULTIPLIERS[i]||'') + post
104
} // formatBytes
105
106
-export function formatSpeed(n: number, options: { digits?: number }={}) {
106
+export function formatSpeed(n: number, options: Parameters<typeof formatBytes>[1]={}) {
107
return formatBytes(n, { post: 'B/s', ...options })
108
}
109
src/log.ts
+10
-3
@@ -71,7 +71,7 @@ const logSpam = defineConfig(CFG.log_spam, false)
71
const debounce = _.debounce(cb => cb(), 1000) // with this technique, i'll be able to debounce some code respecting the references in its closure
72
73
export const logMw: Koa.Middleware = async (ctx, next) => {
74
- const now = new Date()
74
+ const now = new Date() // request start
75
// do it now so it's available for returning plugins
76
ctx.state.completed = Promise.race([ once(ctx.res, 'finish'), once(ctx.res, 'close') ])
77
await next()
@@ -118,8 +118,15 @@ export const logMw: Koa.Middleware = async (ctx, next) => {
118
const user = getCurrentUsername(ctx)
119
const length = ctx.state.length ?? ctx.length
120
const uri = ctx.originalUrl
121
- ctx.logExtra(ctx.state.includesLastByte && ctx.vfsNode && ctx.res.finished && { dl: 1 }
122
- || ctx.state.uploadPath && { size: ctx.state.opTotal, ul: ctx.state.uploads })
121
+ const duration = (Date.now() - Number(now)) / 1000
122
+ ctx.logExtra(ctx.vfsNode && {
123
+ speed: Math.round(length / duration),
124
+ ...ctx.state.includesLastByte && ctx.res.finished && { dl: 1 }
125
+ } || ctx.state.uploadPath && {
126
+ ul: ctx.state.uploads,
127
+ size: ctx.state.opTotal,
128
+ speed: Math.round((ctx.state.opTotal! - (ctx.state.opOffset || 0)) / duration)
129
+ })
130
if (conn?.country)
131
ctx.logExtra({ country: conn.country })
132
if (logUA.get())