mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-31 12:51:35 +02:00
Merge pull request #10227 from overleaf/spd-td-opentelementry
Add opentelemetry to dev environment GitOrigin-RevId: 31a8234197337a264412b411429692525793c8b0
This commit is contained in:
committed by
Copybot
parent
338c6be978
commit
e2ac86adf4
@@ -3,6 +3,7 @@ const os = require('os')
|
||||
const ExpressCompression = require('compression')
|
||||
const promClient = require('prom-client')
|
||||
const promWrapper = require('./prom_wrapper')
|
||||
const tracing = require('./tracing')
|
||||
|
||||
const DEFAULT_APP_NAME = 'unknown'
|
||||
|
||||
@@ -29,6 +30,9 @@ function configure(opts = {}) {
|
||||
*/
|
||||
function initialize(appName, opts = {}) {
|
||||
appName = appName || DEFAULT_APP_NAME
|
||||
if (tracing.tracingEnabled()) {
|
||||
tracing.initialize(appName)
|
||||
}
|
||||
configure({ ...opts, appName })
|
||||
collectDefaultMetrics({ timeout: 5000, prefix: '' })
|
||||
promWrapper.setupSweeping()
|
||||
|
||||
@@ -8,8 +8,17 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@google-cloud/debug-agent": "^5.1.2",
|
||||
"@google-cloud/opentelemetry-cloud-trace-exporter": "^1.1.0",
|
||||
"@google-cloud/profiler": "^4.1.3",
|
||||
"@google-cloud/trace-agent": "^5.1.1",
|
||||
"@opentelemetry/api": "^1.0.4",
|
||||
"@opentelemetry/auto-instrumentations-node": "^0.28.0",
|
||||
"@opentelemetry/exporter-collector": "^0.25.0",
|
||||
"@opentelemetry/exporter-jaeger": "^1.2.0",
|
||||
"@opentelemetry/exporter-trace-otlp-http": "^0.28.0",
|
||||
"@opentelemetry/resources": "^1.2.0",
|
||||
"@opentelemetry/sdk-node": "^0.28.0",
|
||||
"@opentelemetry/semantic-conventions": "^1.2.0",
|
||||
"compression": "^1.7.4",
|
||||
"prom-client": "^11.1.3",
|
||||
"yn": "^3.1.1"
|
||||
|
||||
58
libraries/metrics/tracing.js
Normal file
58
libraries/metrics/tracing.js
Normal file
@@ -0,0 +1,58 @@
|
||||
const opentelemetry = require('@opentelemetry/sdk-node')
|
||||
const {
|
||||
getNodeAutoInstrumentations,
|
||||
} = require('@opentelemetry/auto-instrumentations-node')
|
||||
const {
|
||||
diag,
|
||||
DiagConsoleLogger,
|
||||
DiagLogLevel,
|
||||
trace,
|
||||
} = require('@opentelemetry/api')
|
||||
const { JaegerExporter } = require('@opentelemetry/exporter-jaeger')
|
||||
const { Resource } = require('@opentelemetry/resources')
|
||||
const {
|
||||
SemanticResourceAttributes,
|
||||
} = require('@opentelemetry/semantic-conventions')
|
||||
const GCP = require('@google-cloud/opentelemetry-cloud-trace-exporter')
|
||||
|
||||
let tracer
|
||||
|
||||
function tracingEnabled() {
|
||||
return process.env.GCP_OPENTELEMETRY || process.env.JAEGER_OPENTELEMETRY
|
||||
}
|
||||
|
||||
function initialize(appName) {
|
||||
diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.INFO)
|
||||
|
||||
const resource = new Resource({
|
||||
[SemanticResourceAttributes.SERVICE_NAME]: appName,
|
||||
[SemanticResourceAttributes.SERVICE_NAMESPACE]: 'Overleaf',
|
||||
'host.type': 'VM',
|
||||
})
|
||||
|
||||
let exporter
|
||||
if (process.env.GCP_OPENTELEMETRY) {
|
||||
exporter = new GCP.TraceExporter()
|
||||
} else if (process.env.JAEGER_OPENTELEMETRY) {
|
||||
exporter = new JaegerExporter({ host: process.env.JAEGER_HOST || 'jaeger' })
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
const sdk = new opentelemetry.NodeSDK({
|
||||
traceExporter: exporter,
|
||||
logger: console,
|
||||
|
||||
instrumentations: [getNodeAutoInstrumentations()],
|
||||
resource,
|
||||
})
|
||||
|
||||
tracer = trace.getTracer(appName)
|
||||
sdk.start()
|
||||
}
|
||||
|
||||
function getTracer() {
|
||||
return tracer
|
||||
}
|
||||
|
||||
module.exports = { initialize, getTracer, tracingEnabled }
|
||||
5379
package-lock.json
generated
5379
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1289,6 +1289,7 @@ const ProjectController = {
|
||||
metadata: { viewport: false },
|
||||
showUpgradePrompt,
|
||||
fixedSizeDocument: true,
|
||||
useOpenTelemetry: Settings.useOpenTelemetryClient,
|
||||
})
|
||||
timer.done()
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ function isBodyParserError(nextArg) {
|
||||
|
||||
const wrapBodyParser = method => opts => {
|
||||
const middleware = bodyParser[method](opts)
|
||||
return (req, res, next) => {
|
||||
return function bodyParser(req, res, next) {
|
||||
middleware(req, res, nextArg => {
|
||||
if (isBodyParserError(nextArg)) {
|
||||
return HttpErrorHandler.handleErrorByStatusCode(
|
||||
|
||||
@@ -20,7 +20,7 @@ const RedisStore = require('connect-redis')(session)
|
||||
const bodyParser = require('./BodyParserWrapper')
|
||||
const methodOverride = require('method-override')
|
||||
const cookieParser = require('cookie-parser')
|
||||
const bearerToken = require('express-bearer-token')
|
||||
const bearerTokenMiddleware = require('express-bearer-token')
|
||||
|
||||
const passport = require('passport')
|
||||
const LocalStrategy = require('passport-local').Strategy
|
||||
@@ -67,7 +67,7 @@ if (Settings.behindProxy) {
|
||||
* X-Original-Forwarded-For. Express expects all proxy IPs to be in a comma
|
||||
* separated list in X-Forwarded-For.
|
||||
*/
|
||||
app.use((req, res, next) => {
|
||||
app.use(function getForwardedForHeader(req, res, next) {
|
||||
if (
|
||||
req.headers['x-original-forwarded-for'] &&
|
||||
req.headers['x-forwarded-for']
|
||||
@@ -100,7 +100,7 @@ Object.defineProperty(app.request, 'ip', {
|
||||
return ip
|
||||
},
|
||||
})
|
||||
app.use(function (req, res, next) {
|
||||
app.use(function ignoreAbortedConnections(req, res, next) {
|
||||
if (req.destroyed) {
|
||||
// Request has been aborted already.
|
||||
return
|
||||
@@ -115,7 +115,7 @@ app.use(function (req, res, next) {
|
||||
|
||||
if (Settings.exposeHostname) {
|
||||
const HOSTNAME = require('os').hostname()
|
||||
app.use((req, res, next) => {
|
||||
app.use(function exposeHostname(req, res, next) {
|
||||
res.setHeader('X-Served-By', HOSTNAME)
|
||||
next()
|
||||
})
|
||||
@@ -135,7 +135,8 @@ Modules.registerAppMiddleware(app)
|
||||
app.use(bodyParser.urlencoded({ extended: true, limit: '2mb' }))
|
||||
app.use(bodyParser.json({ limit: Settings.max_json_request_size }))
|
||||
app.use(methodOverride())
|
||||
app.use(bearerToken())
|
||||
// add explicit name for telemetry
|
||||
app.use(bearerTokenMiddleware())
|
||||
|
||||
app.use(metrics.http.monitor(logger))
|
||||
|
||||
@@ -206,7 +207,7 @@ webRouter.use(translations.setLangBasedOnDomainMiddleware)
|
||||
|
||||
if (Settings.cookieRollingSession) {
|
||||
// Measure expiry from last request, not last login
|
||||
webRouter.use(function (req, res, next) {
|
||||
webRouter.use(function touchSession(req, res, next) {
|
||||
if (!req.session.noSessionCallback) {
|
||||
req.session.touch()
|
||||
if (SessionManager.isUserLoggedIn(req.session)) {
|
||||
@@ -229,7 +230,7 @@ expressLocals(webRouter, privateApiRouter, publicApiRouter)
|
||||
|
||||
webRouter.use(SessionAutostartMiddleware.invokeCallbackMiddleware)
|
||||
|
||||
webRouter.use(function (req, res, next) {
|
||||
webRouter.use(function checkIfSiteClosed(req, res, next) {
|
||||
if (Settings.siteIsOpen) {
|
||||
next()
|
||||
} else if (hasAdminAccess(SessionManager.getSessionUser(req.session))) {
|
||||
@@ -239,7 +240,7 @@ webRouter.use(function (req, res, next) {
|
||||
}
|
||||
})
|
||||
|
||||
webRouter.use(function (req, res, next) {
|
||||
webRouter.use(function checkIfEditorClosed(req, res, next) {
|
||||
if (Settings.editorIsOpen) {
|
||||
next()
|
||||
} else if (req.url.indexOf('/admin') === 0) {
|
||||
@@ -253,7 +254,7 @@ webRouter.use(AuthenticationController.validateAdmin)
|
||||
|
||||
// add security headers using Helmet
|
||||
const noCacheMiddleware = require('nocache')()
|
||||
webRouter.use(function (req, res, next) {
|
||||
webRouter.use(function addNoCacheHeader(req, res, next) {
|
||||
const isLoggedIn = SessionManager.isUserLoggedIn(req.session)
|
||||
const isProjectPage = !!req.path.match('^/project/[a-f0-9]{24}$')
|
||||
if (isLoggedIn || isProjectPage) {
|
||||
|
||||
@@ -27,6 +27,7 @@ meta(name="ol-galileoPromptWords" data-type="string" content=galileoPromptWords)
|
||||
meta(name="ol-galileoFeatures" data-type="json" content=galileoFeatures)
|
||||
meta(name="ol-detachRole" data-type="string" content=detachRole)
|
||||
meta(name="ol-showUpgradePrompt" data-type="boolean" content=showUpgradePrompt)
|
||||
meta(name="ol-useOpenTelemetry" data-type="boolean" content=useOpenTelemetry)
|
||||
|
||||
- var fileActionI18n = ['edited', 'renamed', 'created', 'deleted'].reduce((acc, i) => {acc[i] = translate('file_action_' + i); return acc}, {})
|
||||
meta(name="ol-fileActionI18n" data-type="json" content=fileActionI18n)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
* DS207: Consider shorter variations of null checks
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
import '../tracing'
|
||||
import App from './base'
|
||||
import FileTreeManager from './ide/file-tree/FileTreeManager'
|
||||
import LoadingManager from './ide/LoadingManager'
|
||||
@@ -64,7 +65,6 @@ import './features/editor-navigation-toolbar/controllers/editor-navigation-toolb
|
||||
import './features/pdf-preview/controllers/pdf-preview-controller'
|
||||
import './features/share-project-modal/controllers/react-share-project-modal-controller'
|
||||
import './features/source-editor/controllers/editor-switch-controller'
|
||||
import getMeta from './utils/meta'
|
||||
import { cleanupServiceWorker } from './utils/service-worker-cleanup'
|
||||
import { reportCM6Perf } from './infrastructure/cm6-performance'
|
||||
|
||||
|
||||
37
services/web/frontend/tracing.js
Normal file
37
services/web/frontend/tracing.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'
|
||||
import { Resource } from '@opentelemetry/resources'
|
||||
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'
|
||||
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http/build/esnext'
|
||||
import { WebTracerProvider } from '@opentelemetry/sdk-trace-web'
|
||||
import { ZoneContextManager } from '@opentelemetry/context-zone'
|
||||
import { registerInstrumentations } from '@opentelemetry/instrumentation'
|
||||
import { getWebAutoInstrumentations } from '@opentelemetry/auto-instrumentations-web'
|
||||
|
||||
import getMeta from './js/utils/meta'
|
||||
|
||||
if (getMeta('ol-useOpenTelemetry')) {
|
||||
const resource = new Resource({
|
||||
[SemanticResourceAttributes.SERVICE_NAME]: 'frontend',
|
||||
[SemanticResourceAttributes.SERVICE_NAMESPACE]: 'Overleaf',
|
||||
})
|
||||
|
||||
const provider = new WebTracerProvider({ resource })
|
||||
|
||||
provider.addSpanProcessor(
|
||||
new SimpleSpanProcessor(
|
||||
new OTLPTraceExporter({
|
||||
url: `https://${window.location.hostname}/otlp/v1/traces`,
|
||||
})
|
||||
)
|
||||
)
|
||||
|
||||
provider.register({
|
||||
// Changing default contextManager to use ZoneContextManager - supports asynchronous operations - optional
|
||||
contextManager: new ZoneContextManager(),
|
||||
})
|
||||
|
||||
// Registering instrumentations
|
||||
registerInstrumentations({
|
||||
instrumentations: [getWebAutoInstrumentations()],
|
||||
})
|
||||
}
|
||||
@@ -82,6 +82,18 @@
|
||||
"@lezer/common": "^1.0.1",
|
||||
"@lezer/highlight": "^1.1.1",
|
||||
"@lezer/lr": "^1.2.3",
|
||||
"@opentelemetry/api": "^1.0.4",
|
||||
"@opentelemetry/auto-instrumentations-web": "^0.27.2",
|
||||
"@opentelemetry/context-zone": "^1.2.0",
|
||||
"@opentelemetry/exporter-jaeger": "^1.2.0",
|
||||
"@opentelemetry/exporter-trace-otlp-http": "^0.28.0",
|
||||
"@opentelemetry/instrumentation": "^0.27.0",
|
||||
"@opentelemetry/instrumentation-document-load": "^0.27.1",
|
||||
"@opentelemetry/instrumentation-xml-http-request": "^0.28.0",
|
||||
"@opentelemetry/resources": "^1.2.0",
|
||||
"@opentelemetry/sdk-trace-base": "^1.2.0",
|
||||
"@opentelemetry/sdk-trace-web": "^1.2.0",
|
||||
"@opentelemetry/semantic-conventions": "^1.2.0",
|
||||
"@overleaf/logger": "*",
|
||||
"@overleaf/metrics": "*",
|
||||
"@overleaf/o-error": "*",
|
||||
|
||||
Reference in New Issue
Block a user