Skip to content

Commit 5bb5729

Browse files
committed
CLDSRV-750: add Server Access Logs
1 parent d013306 commit 5bb5729

File tree

6 files changed

+378
-1
lines changed

6 files changed

+378
-1
lines changed

config.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,5 +149,9 @@
149149
},
150150
"integrityChecks": {
151151
"objectPutRetention": true
152+
},
153+
"serverAccessLogs": {
154+
"enabled": true,
155+
"outputFile": "./logs/server-access.log"
152156
}
153157
}

lib/Config.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,27 @@ function parseIntegrityChecks(config) {
574574
return integrityChecks;
575575
}
576576

577+
function parseServerAccessLogs(config) {
578+
const res = {
579+
enabled: true,
580+
outputFile: './logs/server-access.log',
581+
};
582+
583+
if (config && config.serverAccessLogs) {
584+
if ('enabled' in config.serverAccessLogs) {
585+
assert(typeof config.serverAccessLogs.enabled === 'boolean');
586+
res.enabled = config.serverAccessLogs.enabled;
587+
}
588+
589+
if ('outputFile' in config.serverAccessLogs) {
590+
assert(typeof config.serverAccessLogs.outputFile === 'string');
591+
res.outputFile = config.serverAccessLogs.outputFile;
592+
}
593+
}
594+
595+
return res;
596+
}
597+
577598
/**
578599
* Reads from a config file and returns the content as a config object
579600
*/
@@ -1785,7 +1806,7 @@ class Config extends EventEmitter {
17851806
}
17861807
}
17871808
this.integrityChecks = parseIntegrityChecks(config);
1788-
1809+
this.serverAccessLogs = parseServerAccessLogs(config);
17891810
/**
17901811
* S3C-10336: PutObject max size of 5GB is new in 9.5.1
17911812
* Provides a way to bypass the new validation if it breaks customer workflows

lib/api/api.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,10 @@ const api = {
264264
});
265265

266266
request.on('end', () => {
267+
if (request.serverAccessLog) {
268+
request.serverAccessLog.startTurnAroundTime = process.hrtime.bigint();
269+
}
270+
267271
if (bodyLength > MAX_BODY_LENGTH) {
268272
log.error('body length is too long for request type',
269273
{ bodyLength });

lib/metadata/metadataUtils.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,23 @@ const { onlyOwnerAllowed } = require('../../constants');
1010
const { actionNeedQuotaCheck, actionWithDataDeletion } = require('arsenal/build/lib/policyEvaluator/RequestContext');
1111
const { processBytesToWrite, validateQuotas } = require('../api/apiUtils/quotas/quotaUtils');
1212

13+
function storeServerAccessLogInfo(request, authInfo, bucket) {
14+
if (request &&
15+
request.serverAccessLog &&
16+
authInfo &&
17+
bucket &&
18+
bucket.getBucketLoggingStatus() &&
19+
bucket.getBucketLoggingStatus().getLoggingEnabled()) {
20+
/* eslint-disable no-param-reassign */
21+
request.serverAccessLog.enabled = true;
22+
request.serverAccessLog.bucketOwner = bucket.getOwner();
23+
request.serverAccessLog.bucketName = bucket.getName();
24+
request.serverAccessLog.authInfo = authInfo;
25+
request.serverAccessLog.loggingEnabled = bucket.getBucketLoggingStatus().getLoggingEnabled();
26+
/* eslint-enable no-param-reassign */
27+
}
28+
}
29+
1330
/** getNullVersionFromMaster - retrieves the null version
1431
* metadata via retrieving the master key
1532
*
@@ -274,6 +291,7 @@ function standardMetadataValidateBucketAndObj(params, actionImplicitDenies, log,
274291
contentLength, withVersionId, log, err => next(err, bucket, objMD));
275292
},
276293
], (err, bucket, objMD) => {
294+
storeServerAccessLogInfo(request, authInfo, bucket);
277295
if (err) {
278296
// still return bucket for cors headers
279297
return callback(err, bucket);
@@ -296,6 +314,7 @@ function standardMetadataValidateBucketAndObj(params, actionImplicitDenies, log,
296314
function standardMetadataValidateBucket(params, actionImplicitDenies, log, callback) {
297315
const { bucketName } = params;
298316
return metadata.getBucket(bucketName, log, (err, bucket) => {
317+
storeServerAccessLogInfo(params.request, params.authInfo, bucket);
299318
if (err) {
300319
// if some implicit actionImplicitDenies, return AccessDenied before
301320
// leaking any state information

lib/server.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const {
2626

2727
const HttpAgent = require('agentkeepalive');
2828
const QuotaService = require('./utilization/instance');
29+
const { logServerAccess } = require('./utilities/serverAccesssLogger');
2930
const { parseLC, MultipleBackendGateway } = arsenal.storage.data;
3031
const websiteEndpoints = _config.websiteEndpoints;
3132
let client = dataWrapper.client;
@@ -122,6 +123,20 @@ class S3Server {
122123
monitoringClient.httpActiveRequests.inc();
123124
const requestStartTime = process.hrtime.bigint();
124125

126+
// eslint-disable-next-line no-param-reassign
127+
req.serverAccessLog = {
128+
enabled: false,
129+
startTime: requestStartTime,
130+
};
131+
// eslint-disable-next-line no-param-reassign
132+
res.serverAccessLog = {};
133+
134+
res.on('finish', () => {
135+
// eslint-disable-next-line no-param-reassign
136+
req.serverAccessLog.endTime = process.hrtime.bigint();
137+
logServerAccess(req.serverAccessLog, req, res);
138+
});
139+
125140
// disable nagle algorithm
126141
req.socket.setNoDelay();
127142
res.on('close', () => {

0 commit comments

Comments
 (0)