Skip to content

Commit

Permalink
feat(logger): support NO_COLOR (#2228)
Browse files Browse the repository at this point in the history
  • Loading branch information
ryuapp authored Feb 25, 2024
1 parent ce2a2f5 commit 3ef39b1
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 34 deletions.
12 changes: 2 additions & 10 deletions deno_dist/helper/dev/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Hono } from '../../hono.ts'
import type { Env, RouterRoute } from '../../types.ts'
import { getColorEnabled } from '../../utils/color.ts'
import { findTargetHandler, isMiddleware } from '../../utils/handler.ts'

interface ShowRoutesOptions {
Expand Down Expand Up @@ -31,16 +32,7 @@ export const inspectRoutes = <E extends Env>(hono: Hono<E>): RouteData[] => {
}

export const showRoutes = <E extends Env>(hono: Hono<E>, opts?: ShowRoutesOptions) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const { process, Deno } = globalThis as any
const isNoColor =
typeof process !== 'undefined'
? // eslint-disable-next-line no-unsafe-optional-chaining
'NO_COLOR' in process?.env
: typeof Deno?.noColor === 'boolean'
? (Deno.noColor as boolean)
: false
const colorEnabled = opts?.colorize ?? !isNoColor
const colorEnabled = opts?.colorize ?? getColorEnabled()
const routeData: Record<string, RouteData[]> = {}
let maxMethodLength = 0
let maxPathLength = 0
Expand Down
16 changes: 9 additions & 7 deletions deno_dist/middleware/logger/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { MiddlewareHandler } from '../../types.ts'
import { getColorEnabled } from '../../utils/color.ts'
import { getPath } from '../../utils/url.ts'

enum LogPrefix {
Expand All @@ -21,14 +22,15 @@ const time = (start: number) => {
}

const colorStatus = (status: number) => {
const colorEnabled = getColorEnabled()
const out: { [key: string]: string } = {
7: `\x1b[35m${status}\x1b[0m`,
5: `\x1b[31m${status}\x1b[0m`,
4: `\x1b[33m${status}\x1b[0m`,
3: `\x1b[36m${status}\x1b[0m`,
2: `\x1b[32m${status}\x1b[0m`,
1: `\x1b[32m${status}\x1b[0m`,
0: `\x1b[33m${status}\x1b[0m`,
7: colorEnabled ? `\x1b[35m${status}\x1b[0m` : `${status}`,
5: colorEnabled ? `\x1b[31m${status}\x1b[0m` : `${status}`,
4: colorEnabled ? `\x1b[33m${status}\x1b[0m` : `${status}`,
3: colorEnabled ? `\x1b[36m${status}\x1b[0m` : `${status}`,
2: colorEnabled ? `\x1b[32m${status}\x1b[0m` : `${status}`,
1: colorEnabled ? `\x1b[32m${status}\x1b[0m` : `${status}`,
0: colorEnabled ? `\x1b[33m${status}\x1b[0m` : `${status}`,
}

const calculateStatus = (status / 100) | 0
Expand Down
12 changes: 12 additions & 0 deletions deno_dist/utils/color.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export function getColorEnabled() {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const { process, Deno } = globalThis as any
const isNoColor =
typeof process !== 'undefined'
? // eslint-disable-next-line no-unsafe-optional-chaining
'NO_COLOR' in process?.env
: typeof Deno?.noColor === 'boolean'
? (Deno.noColor as boolean)
: false
return !isNoColor
}
12 changes: 2 additions & 10 deletions src/helper/dev/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Hono } from '../../hono'
import type { Env, RouterRoute } from '../../types'
import { getColorEnabled } from '../../utils/color'
import { findTargetHandler, isMiddleware } from '../../utils/handler'

interface ShowRoutesOptions {
Expand Down Expand Up @@ -31,16 +32,7 @@ export const inspectRoutes = <E extends Env>(hono: Hono<E>): RouteData[] => {
}

export const showRoutes = <E extends Env>(hono: Hono<E>, opts?: ShowRoutesOptions) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const { process, Deno } = globalThis as any
const isNoColor =
typeof process !== 'undefined'
? // eslint-disable-next-line no-unsafe-optional-chaining
'NO_COLOR' in process?.env
: typeof Deno?.noColor === 'boolean'
? (Deno.noColor as boolean)
: false
const colorEnabled = opts?.colorize ?? !isNoColor
const colorEnabled = opts?.colorize ?? getColorEnabled()
const routeData: Record<string, RouteData[]> = {}
let maxMethodLength = 0
let maxPathLength = 0
Expand Down
77 changes: 77 additions & 0 deletions src/middleware/logger/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,80 @@ describe('Logger by Middleware', () => {
expect(log).toMatch(/m?s$/)
})
})

describe('Logger by Middleware in NO_COLOR', () => {
let app: Hono
let log: string

beforeEach(() => {
vi.stubEnv('NO_COLOR', '1')
function sleep(time: number) {
return new Promise((resolve) => setTimeout(resolve, time))
}

app = new Hono()

const logFn = (str: string) => {
log = str
}

const shortRandomString = 'hono'
const longRandomString = 'hono'.repeat(1000)

app.use('*', logger(logFn))
app.get('/short', (c) => c.text(shortRandomString))
app.get('/long', (c) => c.text(longRandomString))
app.get('/seconds', async (c) => {
await sleep(1000)

return c.text(longRandomString)
})
app.get('/empty', (c) => c.text(''))
})
afterAll(() => {
vi.unstubAllEnvs()
})
it('Log status 200 with empty body', async () => {
const res = await app.request('http://localhost/empty')
expect(res).not.toBeNull()
expect(res.status).toBe(200)
expect(log.startsWith(' --> GET /empty 200')).toBe(true)
expect(log).toMatch(/m?s$/)
})

it('Log status 200 with small body', async () => {
const res = await app.request('http://localhost/short')
expect(res).not.toBeNull()
expect(res.status).toBe(200)
expect(log.startsWith(' --> GET /short 200')).toBe(true)
expect(log).toMatch(/m?s$/)
})

it('Log status 200 with big body', async () => {
const res = await app.request('http://localhost/long')
expect(res).not.toBeNull()
expect(res.status).toBe(200)
expect(log.startsWith(' --> GET /long 200')).toBe(true)
expect(log).toMatch(/m?s$/)
})

it('Time in seconds', async () => {
const res = await app.request('http://localhost/seconds')
expect(res).not.toBeNull()
expect(res.status).toBe(200)
expect(log.startsWith(' --> GET /seconds 200')).toBe(true)
expect(log).toMatch(/1s/)
})

it('Log status 404', async () => {
const msg = 'Default 404 Not Found'
app.all('*', (c) => {
return c.text(msg, 404)
})
const res = await app.request('http://localhost/notfound')
expect(res).not.toBeNull()
expect(res.status).toBe(404)
expect(log.startsWith(' --> GET /notfound 404')).toBe(true)
expect(log).toMatch(/m?s$/)
})
})
16 changes: 9 additions & 7 deletions src/middleware/logger/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { MiddlewareHandler } from '../../types'
import { getColorEnabled } from '../../utils/color'
import { getPath } from '../../utils/url'

enum LogPrefix {
Expand All @@ -21,14 +22,15 @@ const time = (start: number) => {
}

const colorStatus = (status: number) => {
const colorEnabled = getColorEnabled()
const out: { [key: string]: string } = {
7: `\x1b[35m${status}\x1b[0m`,
5: `\x1b[31m${status}\x1b[0m`,
4: `\x1b[33m${status}\x1b[0m`,
3: `\x1b[36m${status}\x1b[0m`,
2: `\x1b[32m${status}\x1b[0m`,
1: `\x1b[32m${status}\x1b[0m`,
0: `\x1b[33m${status}\x1b[0m`,
7: colorEnabled ? `\x1b[35m${status}\x1b[0m` : `${status}`,
5: colorEnabled ? `\x1b[31m${status}\x1b[0m` : `${status}`,
4: colorEnabled ? `\x1b[33m${status}\x1b[0m` : `${status}`,
3: colorEnabled ? `\x1b[36m${status}\x1b[0m` : `${status}`,
2: colorEnabled ? `\x1b[32m${status}\x1b[0m` : `${status}`,
1: colorEnabled ? `\x1b[32m${status}\x1b[0m` : `${status}`,
0: colorEnabled ? `\x1b[33m${status}\x1b[0m` : `${status}`,
}

const calculateStatus = (status / 100) | 0
Expand Down
18 changes: 18 additions & 0 deletions src/utils/color.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { getColorEnabled } from './color'

describe('getColorEnabled()', () => {
it('getColorEnabled() is true', async () => {
expect(getColorEnabled()).toBe(true)
})
})
describe('getColorEnabled() in NO_COLOR', () => {
beforeAll(() => {
vi.stubEnv('NO_COLOR', '1')
})
afterAll(() => {
vi.unstubAllEnvs()
})
it('getColorEnabled() is false', async () => {
expect(getColorEnabled()).toBe(false)
})
})
12 changes: 12 additions & 0 deletions src/utils/color.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export function getColorEnabled() {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const { process, Deno } = globalThis as any
const isNoColor =
typeof process !== 'undefined'
? // eslint-disable-next-line no-unsafe-optional-chaining
'NO_COLOR' in process?.env
: typeof Deno?.noColor === 'boolean'
? (Deno.noColor as boolean)
: false
return !isNoColor
}

0 comments on commit 3ef39b1

Please sign in to comment.