-
Notifications
You must be signed in to change notification settings - Fork 33
/
express.ts
115 lines (105 loc) · 3.46 KB
/
express.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*!
* Copyright 2018 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
HttpRequest,
middleware as commonMiddleware,
} from '@google-cloud/logging';
import * as bunyan from 'bunyan';
import {GCPEnv} from 'google-auth-library';
import {
LOGGING_TRACE_KEY,
LOGGING_SPAN_KEY,
LOGGING_SAMPLED_KEY,
LoggingBunyan,
} from '../index';
import * as types from '../types/core';
export const APP_LOG_SUFFIX = 'applog';
// @types/bunyan doesn't export Logger. Access it via ReturnType on
// createLogger.
export type Logger = ReturnType<typeof bunyan.createLogger>;
export interface MiddlewareOptions extends types.Options {
level?: types.LogLevel;
}
export interface MiddlewareReturnType {
logger: Logger;
mw: ReturnType<typeof commonMiddleware.express.makeMiddleware>;
}
/**
* Express middleware
*/
export async function middleware(
options?: MiddlewareOptions
): Promise<MiddlewareReturnType> {
const defaultOptions = {logName: 'bunyan_log', level: 'info'};
options = Object.assign({}, defaultOptions, options);
const loggingBunyanApp = new LoggingBunyan(
Object.assign({}, options, {
// For request bundling to work, the parent (request) and child (app) logs
// need to have distinct names. For exact requirements see:
// https://cloud.google.com/appengine/articles/logging#linking_app_logs_and_requests
logName: `${options.logName}_${APP_LOG_SUFFIX}`,
})
);
const logger = bunyan.createLogger({
name: `${options.logName}_${APP_LOG_SUFFIX}`,
streams: [loggingBunyanApp.stream(options.level as types.LogLevel)],
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const auth = (loggingBunyanApp.cloudLog as any).logging.auth;
const [env, projectId] = await Promise.all([
auth.getEnv(),
auth.getProjectId(),
]);
// Unless we are running on Google App Engine or Cloud Functions, generate a
// parent request log entry that all the request-specific logs ("app logs")
// will nest under. GAE and GCF generate the parent request logs
// automatically.
let emitRequestLog;
if (env !== GCPEnv.APP_ENGINE && env !== GCPEnv.CLOUD_FUNCTIONS) {
const loggingBunyanReq = new LoggingBunyan(options);
const requestLogger = bunyan.createLogger({
name: options.logName!,
streams: [loggingBunyanReq.stream(options.level as types.LogLevel)],
});
emitRequestLog = (
httpRequest: HttpRequest,
trace: string,
span?: string,
sampled?: boolean
) => {
requestLogger.info({
[LOGGING_TRACE_KEY]: trace,
[LOGGING_SPAN_KEY]: span,
[LOGGING_SAMPLED_KEY]: sampled,
httpRequest,
});
};
}
return {
logger,
mw: commonMiddleware.express.makeMiddleware(
projectId,
makeChildLogger,
emitRequestLog
),
};
function makeChildLogger(trace: string, span?: string) {
return logger.child(
{[LOGGING_TRACE_KEY]: trace, [LOGGING_SPAN_KEY]: span},
true /* simple child */
);
}
}