Created
March 29, 2023 13:56
-
-
Save AlexMachin1997/09fb1632aadf7cd191ae6510dbd1e516 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const metricsService = require("../services/MetricsService"); | |
const logger = require("../utils/Logger"); | |
/** | |
* The GET action for /api/v1.0.0/metrics | |
*/ | |
exports.download = (_, res) => { | |
try { | |
// Get the in memory metrics file (Either comes from /metrics folder in the project or the kubernetes persistent storage) | |
const { name, contentType, lastModified, size } = | |
metricsService.getMetadata(); | |
// Create a read stream to retrieve the file from storage | |
const stream = metricsService.createReadStream(); | |
// When a stream error occurs throw that error and pass it to the catch block below | |
stream.on("error", (error) => new Error(error)); | |
// Provided the stream hasn't error log the successful download message | |
logger.info("Metrics file has been downloaded successfully"); | |
// Set the downloader headers only after no more errors have occurred | |
res.header("Content-Disposition", `attachment; filename="${name}"`); | |
res.header("Content-Type", contentType); | |
res.header("Content-Length", size); | |
res.header("Last-Modified", lastModified); | |
// Return the found file in a binary format | |
stream.pipe(res); | |
} catch (error) { | |
// error retrieving the file from disk | |
logger.error(`Cannot download metrics file: ${error.message}`, error); | |
// We do not want to disclose the actual detailed error to the client | |
const fileNotFound = error?.message?.includes("ENOENT") ?? false; | |
// Since the download failed either set the status to 404 (File not found) or 500 (Internal server error) | |
res.statusCode = fileNotFound ? 404 : 500; | |
// Return the error object | |
res.send({ | |
name: error.name, | |
message: fileNotFound | |
? "The file is not found" | |
: "An unexpected error occurred retrieving the file", | |
}); | |
} | |
}; | |
/** | |
* The PUT action for /api/v1.0.0/metrics | |
*/ | |
exports.upload = (req, res) => { | |
try { | |
const stream = metricsService.createWriteStream(); | |
// When a stream error occurs throw that error and pass it to the catch block below | |
stream.on("error", (error) => new Error(error)); | |
// Provided the stream hasn't error log the successful upload message | |
logger.info("Metrics file has been updated successfully"); | |
// Since the upload has been successful and there is no content return a 204 http status | |
res.statusCode = 204; | |
// Required to make sure that the request ends after doing everything above | |
// NOTE: Without piping the contents of the request you won't be able to retrieve then properly next time you request the file you uploaded (Weird I know......) | |
req.pipe(stream); | |
} catch (error) { | |
logger.error(`Cannot upload metrics file: ${error.message}`, error); | |
// Since the upload failed set the status 500 | |
res.statusCode = 500; | |
// Return the error object | |
res.send({ | |
name: error.name, | |
message: "An unexpected error occurred saving the file", | |
}); | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const path = require("path"); | |
const fs = require("fs"); | |
const mime = require("mime"); | |
const configService = require("./ConfigService"); | |
const BaseService = require("./BaseService"); | |
/** | |
* The metrics service. | |
*/ | |
class MetricsService extends BaseService { | |
constructor() { | |
super(); | |
const getMetricsFileName = () => { | |
const { filePath } = configService.getMetrics(); | |
return filePath; | |
}; | |
/** | |
* Gets the metrics metadata. | |
* @returns | |
*/ | |
this.getMetadata = () => { | |
const fileName = getMetricsFileName(); | |
const name = path.basename(fileName); | |
const contentType = mime.getType(fileName); | |
const stats = fs.statSync(fileName); | |
const { size, mtime: lastModified } = stats; | |
return { | |
name, | |
contentType, | |
lastModified, | |
size, | |
}; | |
}; | |
/** | |
* Gets the metrics readable stream. | |
* @Returns The metrics stream. | |
*/ | |
this.createReadStream = () => { | |
const fileName = getMetricsFileName(); | |
return fs.createReadStream(fileName); | |
}; | |
/** | |
* Gets the metrics writeable stream. | |
* @Returns The metrics stream. | |
*/ | |
this.createWriteStream = () => { | |
const fileName = getMetricsFileName(); | |
return fs.createWriteStream(fileName); | |
}; | |
} | |
} | |
module.exports = new MetricsService(); // expose the singleton instance so NodeJS can cache it |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment