Skip to content

Commit

Permalink
Add event for dev process stop (#42255)
Browse files Browse the repository at this point in the history
x-ref: [slack
thread](https://vercel.slack.com/archives/C02HEJASXGD/p1667173179573409?thread_ts=1667165920.338789&channel=C02HEJASXGD&message_ts=1667173179.573409)

## Bug

- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have a helpful link attached, see `contributing.md`

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the
feature request has been accepted for implementation before opening a
PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have a helpful link attached, see `contributing.md`

## Documentation / Examples

- [ ] Make sure the linting passes by running `pnpm build && pnpm lint`
- [ ] The "examples guidelines" are followed from [our contributing
doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md)
  • Loading branch information
ijjk committed Oct 31, 2022
1 parent a4f9d77 commit 96696c2
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 4 deletions.
2 changes: 1 addition & 1 deletion packages/next/bin/next.ts
Expand Up @@ -113,7 +113,7 @@ if (process.versions.pnp === '3') {

// Make sure commands gracefully respect termination signals (e.g. from Docker)
// Allow the graceful termination to be manually configurable
if (!process.env.NEXT_MANUAL_SIG_HANDLE) {
if (!process.env.NEXT_MANUAL_SIG_HANDLE && command !== 'dev') {
process.on('SIGTERM', () => process.exit(0))
process.on('SIGINT', () => process.exit(0))
}
Expand Down
43 changes: 40 additions & 3 deletions packages/next/cli/next-dev.ts
Expand Up @@ -11,9 +11,39 @@ import { getProjectDir } from '../lib/get-project-dir'
import { CONFIG_FILES } from '../shared/lib/constants'
import path from 'path'
import type { NextConfig } from '../types'
import { interopDefault } from '../lib/interop-default'
import { Telemetry } from '../telemetry/storage'
import { NextConfigComplete } from '../server/config-shared'
import type { NextConfigComplete } from '../server/config-shared'
import { traceGlobals } from '../trace/shared'

let isTurboSession = false
let sessionStopHandled = false
let sessionStarted = Date.now()

const handleSessionStop = async () => {
if (sessionStopHandled) return
sessionStopHandled = true

const { eventCliSession } =
require('../telemetry/events/session-stopped') as typeof import('../telemetry/events/session-stopped')
const telemetry = traceGlobals.get('telemetry') as InstanceType<
typeof import('../telemetry/storage').Telemetry
>
if (!telemetry) {
process.exit(0)
}

telemetry.record(
eventCliSession({
cliCommand: 'dev',
turboFlag: isTurboSession,
durationMilliseconds: Date.now() - sessionStarted,
})
)
await telemetry.flush()
process.exit(0)
}

process.on('SIGINT', handleSessionStop)
process.on('SIGTERM', handleSessionStop)

const nextDev: cliCommand = (argv) => {
const validArgs: arg.Spec = {
Expand Down Expand Up @@ -105,6 +135,7 @@ const nextDev: cliCommand = (argv) => {
}

if (args['--turbo']) {
isTurboSession = true
// check for postcss, babelrc, swc plugins
return new Promise<void>(async (resolve) => {
const { findConfigPath } =
Expand All @@ -127,6 +158,11 @@ const nextDev: cliCommand = (argv) => {
require('../telemetry/events/version') as typeof import('../telemetry/events/version')
const { findPagesDir } =
require('../lib/find-pages-dir') as typeof import('../lib/find-pages-dir')
const { interopDefault } =
require('../lib/interop-default') as typeof import('../lib/interop-default')
const { setGlobal } = require('../trace') as typeof import('../trace')
const { Telemetry } =
require('../telemetry/storage') as typeof import('../telemetry/storage')

// To regenerate the TURBOPACK gradient require('gradient-string')('blue', 'red')('>>> TURBOPACK')
const isTTY = process.stdout.isTTY
Expand Down Expand Up @@ -293,6 +329,7 @@ If you cannot make the changes above, but still want to try out\nNext.js v13 wit
const telemetry = new Telemetry({
distDir,
})
setGlobal('telemetry', telemetry)

telemetry.record(
eventCliSession(distDir, rawNextConfig as NextConfigComplete, {
Expand Down
31 changes: 31 additions & 0 deletions packages/next/telemetry/events/session-stopped.ts
@@ -0,0 +1,31 @@
const EVENT_VERSION = 'NEXT_CLI_SESSION_STOPPED'

export type EventCliSessionStopped = {
cliCommand: string
nextVersion: string
nodeVersion: string
turboFlag?: boolean | null
durationMilliseconds?: number | null
}

export function eventCliSession(
event: Omit<EventCliSessionStopped, 'nextVersion' | 'nodeVersion'>
): { eventName: string; payload: EventCliSessionStopped }[] {
// This should be an invariant, if it fails our build tooling is broken.
if (typeof process.env.__NEXT_VERSION !== 'string') {
return []
}

const payload: EventCliSessionStopped = {
nextVersion: process.env.__NEXT_VERSION,
nodeVersion: process.version,
cliCommand: event.cliCommand,
durationMilliseconds: event.durationMilliseconds,
...(typeof event.turboFlag !== 'undefined'
? {
turboFlag: !!event.turboFlag,
}
: {}),
}
return [{ eventName: EVENT_VERSION, payload }]
}
56 changes: 56 additions & 0 deletions test/integration/telemetry/test/index.test.js
Expand Up @@ -10,6 +10,7 @@ import {
waitFor,
nextBuild,
nextLint,
check,
} from 'next-test-utils'

const appDir = path.join(__dirname, '..')
Expand Down Expand Up @@ -394,6 +395,61 @@ describe('Telemetry CLI', () => {
expect(event1).toMatch(/"turboFlag": true/)
})

it('detects --turbo correctly for `next dev` stopped', async () => {
let port = await findPort()
let stderr = ''

const handleStderr = (msg) => {
stderr += msg
}
let app = await launchApp(appDir, port, {
onStderr: handleStderr,
env: {
NEXT_TELEMETRY_DEBUG: 1,
},
turbo: true,
})

if (app) {
await killApp(app)
}
await check(() => stderr, /NEXT_CLI_SESSION_STOPPED/)

const event1 = /NEXT_CLI_SESSION_STOPPED[\s\S]+?{([\s\S]+?)}/
.exec(stderr)
.pop()

expect(event1).toMatch(/"turboFlag": true/)
})

it('detects correctly for `next dev` stopped (no turbo)', async () => {
let port = await findPort()
let stderr = ''

const handleStderr = (msg) => {
stderr += msg
}
let app = await launchApp(appDir, port, {
onStderr: handleStderr,
env: {
NEXT_TELEMETRY_DEBUG: 1,
},
})

await check(() => stderr, /NEXT_CLI_SESSION_STARTED/)

if (app) {
await killApp(app)
}
await check(() => stderr, /NEXT_CLI_SESSION_STOPPED/)

const event1 = /NEXT_CLI_SESSION_STOPPED[\s\S]+?{([\s\S]+?)}/
.exec(stderr)
.pop()

expect(event1).toMatch(/"turboFlag": false/)
})

it('detect reportWebVitals correctly for `next build`', async () => {
// Case 1: When _app.js does not exist.
let build = await nextBuild(appDir, [], {
Expand Down

0 comments on commit 96696c2

Please sign in to comment.