mirror of
https://github.com/overleaf/overleaf.git
synced 2024-12-24 02:31:29 +00:00
010476a60f
[misc] step up logging (for github-sync) GitOrigin-RevId: 9e7481d92e51f4f986f50a018a602c53aca78500
130 lines
3.4 KiB
JavaScript
130 lines
3.4 KiB
JavaScript
const bunyan = require('bunyan')
|
|
|
|
/**
|
|
* When we copy log entry fields, omit some bunyan core fields that are not
|
|
* interesting, that have a special meaning in GCP, or that we will process
|
|
* separately.
|
|
*/
|
|
const ENTRY_FIELDS_TO_OMIT = [
|
|
'level',
|
|
'name',
|
|
'hostname',
|
|
'v',
|
|
'pid',
|
|
'msg',
|
|
'err',
|
|
'req',
|
|
'res',
|
|
]
|
|
|
|
/**
|
|
* Convert a bunyan log entry to a format that GCP understands
|
|
*/
|
|
function convertLogEntry(entry) {
|
|
const gcpEntry = omit(entry, ENTRY_FIELDS_TO_OMIT)
|
|
|
|
// Error information. In GCP, the stack trace goes in the message property.
|
|
// This enables the error reporting feature.
|
|
if (entry.err) {
|
|
if (entry.err.info) {
|
|
Object.assign(gcpEntry, entry.err.info)
|
|
}
|
|
if (entry.err.code) {
|
|
gcpEntry.code = entry.err.code
|
|
}
|
|
if (entry.err.signal) {
|
|
gcpEntry.signal = entry.err.signal
|
|
}
|
|
if (entry.err.stack !== '(no stack)') {
|
|
gcpEntry.message = entry.err.stack
|
|
} else if (entry.err.message) {
|
|
gcpEntry.message = entry.err.message
|
|
}
|
|
if (entry.name) {
|
|
gcpEntry.serviceContext = { service: entry.name }
|
|
}
|
|
}
|
|
|
|
// Log message
|
|
if (entry.msg) {
|
|
if (gcpEntry.message) {
|
|
// A message has already been extracted from the error. Keep the extra
|
|
// message in the msg property.
|
|
gcpEntry.msg = entry.msg
|
|
} else {
|
|
gcpEntry.message = entry.msg
|
|
}
|
|
}
|
|
|
|
// Severity
|
|
if (entry.level) {
|
|
gcpEntry.severity = bunyan.nameFromLevel[entry.level]
|
|
}
|
|
|
|
// HTTP request information
|
|
if (entry.req || entry.res || entry.responseTimeMs) {
|
|
const httpRequest = {}
|
|
if (entry.req) {
|
|
const req = entry.req
|
|
httpRequest.requestMethod = req.method
|
|
httpRequest.requestUrl = req.url
|
|
httpRequest.remoteIp = req.remoteAddress
|
|
if (req.headers) {
|
|
if (req.headers['content-length']) {
|
|
httpRequest.requestSize = parseInt(req.headers['content-length'], 10)
|
|
}
|
|
httpRequest.userAgent = req.headers['user-agent']
|
|
httpRequest.referer = req.headers.referer
|
|
}
|
|
}
|
|
|
|
if (entry.res) {
|
|
const res = entry.res
|
|
httpRequest.status = res.statusCode
|
|
if (res.headers && res.headers['content-length']) {
|
|
if (res.headers['content-length']) {
|
|
httpRequest.responseSize = parseInt(res.headers['content-length'], 10)
|
|
}
|
|
}
|
|
}
|
|
|
|
if (entry.responseTimeMs) {
|
|
const responseTimeSec = entry.responseTimeMs / 1000
|
|
httpRequest.latency = `${responseTimeSec}s`
|
|
}
|
|
gcpEntry.httpRequest = httpRequest
|
|
}
|
|
|
|
// Labels are indexed in GCP. We copy the project, doc and user ids to labels to enable fast filtering
|
|
const projectId =
|
|
gcpEntry.projectId ||
|
|
gcpEntry.project_id ||
|
|
(entry.req && entry.req.projectId)
|
|
const userId =
|
|
gcpEntry.userId || gcpEntry.user_id || (entry.req && entry.req.userId)
|
|
const docId =
|
|
gcpEntry.docId || gcpEntry.doc_id || (entry.req && entry.req.docId)
|
|
if (projectId || userId || docId) {
|
|
const labels = {}
|
|
if (projectId) {
|
|
labels.projectId = projectId
|
|
}
|
|
if (userId) {
|
|
labels.userId = userId
|
|
}
|
|
if (docId) {
|
|
labels.docId = docId
|
|
}
|
|
gcpEntry['logging.googleapis.com/labels'] = labels
|
|
}
|
|
|
|
return gcpEntry
|
|
}
|
|
|
|
function omit(obj, excludedFields) {
|
|
return Object.fromEntries(
|
|
Object.entries(obj).filter(([key]) => !excludedFields.includes(key))
|
|
)
|
|
}
|
|
|
|
module.exports = { convertLogEntry }
|