Skip to content

Commit 2816948

Browse files
Ebonsignoriheiskr
andauthored
add manual and automatic backend loggers (#54372)
Co-authored-by: Kevin Heis <[email protected]>
1 parent 642be22 commit 2816948

File tree

20 files changed

+1941
-75
lines changed

20 files changed

+1941
-75
lines changed

next.config.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import fs from 'fs'
22
import path from 'path'
33

44
import frontmatter from 'gray-matter'
5+
import { getLogLevelNumber } from '#src/observability/logger/lib/log-levels.js'
6+
57
// Replace imports with hardcoded values
68
const ROOT = process.env.ROOT || '.'
79

@@ -35,6 +37,9 @@ export default {
3537
'mixed-decls',
3638
],
3739
},
40+
// Don't use automatic Next.js logging in dev unless the log level is `debug` or higher
41+
// See `src/observability/logger/README.md` for log levels
42+
logging: getLogLevelNumber() < 3 ? false : {},
3843
async rewrites() {
3944
const DEFAULT_VERSION = 'free-pro-team@latest'
4045
return productIds.map((productId) => {
@@ -47,7 +52,7 @@ export default {
4752
webpack: (config) => {
4853
config.experiments = config.experiments || {}
4954
config.experiments.topLevelAwait = true
50-
config.resolve.fallback = { fs: false }
55+
config.resolve.fallback = { fs: false, async_hooks: false }
5156
return config
5257
},
5358

package-lock.json

Lines changed: 0 additions & 48 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,6 @@
306306
"mdast-util-to-hast": "^13.2.0",
307307
"mdast-util-to-markdown": "2.1.2",
308308
"mdast-util-to-string": "^4.0.0",
309-
"morgan": "^1.10.1",
310309
"next": "^15.3.3",
311310
"ora": "^8.0.1",
312311
"parse5": "7.1.2",
@@ -361,7 +360,6 @@
361360
"@types/lodash": "^4.17.16",
362361
"@types/lodash-es": "4.17.12",
363362
"@types/mdast": "^4.0.4",
364-
"@types/morgan": "1.9.9",
365363
"@types/react": "18.3.20",
366364
"@types/react-dom": "^18.3.6",
367365
"@types/semver": "^7.5.8",

src/frame/lib/warm-server.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import statsd from '@/observability/lib/statsd'
22
import { loadUnversionedTree, loadSiteTree, loadPages, loadPageMap } from './page-data'
33
import loadRedirects from '@/redirects/lib/precompile'
4+
import { createLogger } from '@/observability/logger'
5+
6+
const logger = createLogger(import.meta.url)
47

58
// Instrument these functions so that
69
// it's wrapped in a timer that reports to Datadog
@@ -19,12 +22,9 @@ let promisedWarmServer: any
1922
async function warmServer(languagesOnly = []) {
2023
const startTime = Date.now()
2124

22-
if (process.env.NODE_ENV !== 'test') {
23-
console.log(
24-
'Priming context information...',
25-
languagesOnly && languagesOnly.length ? `${languagesOnly.join(',')} only` : '',
26-
)
27-
}
25+
logger.debug(
26+
`Priming context information...${languagesOnly && languagesOnly.length ? ` ${languagesOnly.join(',')} only` : ''}`,
27+
)
2828

2929
const unversionedTree = await dog.loadUnversionedTree(languagesOnly)
3030
const siteTree = await dog.loadSiteTree(unversionedTree, languagesOnly)
@@ -34,9 +34,7 @@ async function warmServer(languagesOnly = []) {
3434

3535
statsd.gauge('memory_heap_used', process.memoryUsage().heapUsed, ['event:warm-server'])
3636

37-
if (process.env.NODE_ENV !== 'test') {
38-
console.log(`Context primed in ${Date.now() - startTime} ms`)
39-
}
37+
logger.debug(`Context primed in ${Date.now() - startTime} ms`)
4038

4139
return {
4240
pages: pageMap,

src/frame/middleware/context/context.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import productNames from '@/products/lib/product-names'
1717
import warmServer from '@/frame/lib/warm-server'
1818
import nonEnterpriseDefaultVersion from '@/versions/lib/non-enterprise-default-version'
1919
import { getDataByLanguage, getUIDataMerged } from '@/data-directory/lib/get-data'
20+
import { updateLoggerContext } from '@/observability/logger/lib/logger-context'
2021

2122
// This doesn't change just because the request changes, so compute it once.
2223
const enterpriseServerVersions = Object.keys(allVersions).filter((version) =>
@@ -107,5 +108,10 @@ export default async function contextualize(
107108
}
108109
}
109110

111+
updateLoggerContext({
112+
version: req.context.currentVersion,
113+
pagePath: req.pagePath,
114+
})
115+
110116
return next()
111117
}

src/frame/middleware/index.ts

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import timeout from 'connect-timeout'
77

88
import { haltOnDroppedConnection } from './halt-on-dropped-connection'
99
import abort from './abort'
10-
import morgan from 'morgan'
1110
import helmet from './helmet'
1211
import cookieParser from './cookie-parser'
1312
import {
@@ -64,17 +63,12 @@ import dynamicAssets from '@/assets/middleware/dynamic-assets'
6463
import generalSearchMiddleware from '@/search/middleware/general-search-middleware'
6564
import shielding from '@/shielding/middleware'
6665
import { MAX_REQUEST_TIMEOUT } from '@/frame/lib/constants'
66+
import { initLoggerContext } from '@/observability/logger/lib/logger-context'
67+
import { getAutomaticRequestLogger } from '@/observability/logger/middleware/get-automatic-request-logger'
6768

6869
const { NODE_ENV } = process.env
6970
const isTest = NODE_ENV === 'test' || process.env.GITHUB_ACTIONS === 'true'
7071

71-
// By default, logging each request (with morgan), is on. And by default
72-
// it's off if you're in a production environment or running automated tests.
73-
// But if you set the env var, that takes precedence.
74-
const ENABLE_DEV_LOGGING = Boolean(
75-
process.env.ENABLE_DEV_LOGGING ? JSON.parse(process.env.ENABLE_DEV_LOGGING) : !isTest,
76-
)
77-
7872
const ENABLE_FASTLY_TESTING = JSON.parse(process.env.ENABLE_FASTLY_TESTING || 'false')
7973

8074
// Catch unhandled promise rejections and passing them to Express's error handler
@@ -104,10 +98,9 @@ export default function (app: Express) {
10498
//
10599
app.set('trust proxy', true)
106100

107-
// *** Request logging ***
108-
if (ENABLE_DEV_LOGGING) {
109-
app.use(morgan('dev'))
110-
}
101+
// *** Logging ***
102+
app.use(initLoggerContext) // Context for both inline logs (e.g. logger.info) and automatic logs
103+
app.use(getAutomaticRequestLogger()) // Automatic logging for all requests e.g. "GET /path 200"
111104

112105
// Put this early to make it as fast as possible because it's used
113106
// to check the health of each cluster.

src/frame/server.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import { main } from './start-server'
2+
import { createLogger } from '@/observability/logger'
3+
4+
const logger = createLogger(import.meta.url)
25

36
try {
47
await main()
58
} catch (error) {
6-
console.error(error)
9+
logger.error('Uncaught top-level error', { error })
710
}

src/languages/middleware/detect-language.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { Language as parserLanguage } from 'accept-language-parser'
55
import languages, { languageKeys } from '@/languages/lib/languages'
66
import { USER_LANGUAGE_COOKIE_NAME } from '@/frame/lib/constants'
77
import type { ExtendedRequest, Languages } from '@/types'
8+
import { updateLoggerContext } from '@/observability/logger/lib/logger-context'
89

910
const chineseRegions = [
1011
'CN', // Mainland
@@ -70,5 +71,9 @@ export default function detectLanguage(req: ExtendedRequest, res: Response, next
7071
if (!req.userLanguage) {
7172
req.userLanguage = getLanguageCodeFromHeader(req)
7273
}
74+
updateLoggerContext({
75+
language: req.language,
76+
userLanguage: req.userLanguage,
77+
})
7378
return next()
7479
}

src/observability/README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
# Observability
22

3-
Observability, for lack of simpler term, is our ability to collect data about how the Docs operates. These tools allow us to monitor the health of our systems, catch any errors, and get paged if a system stops working.
3+
Observability, for lack of simpler term, is our ability to collect data about how the Docs operates. These tools allow us to monitor the health of our systems, catch any errors, and get paged if a system stops working.
44

55
In this directory we have files that connect us to our observability tools, as well as high-level error handling that helps keep our systems resilient.
66

77
We collect data in our observability systems to track the health of the Docs systems, not to track user behaviors. User behavior data collection is under the `src/events` directory.
8+
9+
## Logging
10+
11+
Please see the [logger README](./logger/README.md).

src/observability/lib/failbot.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import got, { type OptionsOfTextResponseBody, type Method } from 'got'
22
import { Failbot, HTTPBackend } from '@github/failbot'
3+
import { getLoggerContext } from '@/observability/logger/lib/logger-context'
34

45
const HAYSTACK_APP = 'docs'
56

@@ -62,7 +63,15 @@ export function report(error: Error, metadata?: Record<string, unknown>) {
6263
backends,
6364
})
6465

65-
return failbot.report(error, metadata)
66+
// Add the request id from the logger context to the metadata
67+
// Per https://github.com/github/failbotg/blob/main/docs/api.md#additional-data
68+
// Metadata can only be a flat object with string & number values, so only add the requestUuid
69+
const loggerContext = getLoggerContext()
70+
71+
return failbot.report(error, {
72+
...metadata,
73+
requestUuid: loggerContext.requestUuid || 'unknown',
74+
})
6675
}
6776

6877
// Kept for legacy so you can continue to do:

0 commit comments

Comments
 (0)