Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prerender structured logging #1385

Merged
merged 5 commits into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/prerender-fargate/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1 @@
!lib/prerender/*
!lib/prerender/**
2 changes: 1 addition & 1 deletion packages/prerender-fargate/lib/prerender-fargate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ export class PrerenderFargate extends Construct {
),
unhealthyThresholdCount:
prerenderFargateScalingOptions?.unhealthyThresholdCount || 5,
healthyHttpCodes: "401",
healthyHttpCodes: "200",
});

// Setup AutoScaling policy
Expand Down
9 changes: 4 additions & 5 deletions packages/prerender-fargate/lib/prerender/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,18 @@ ENV CHROME_BIN=/usr/bin/chromium-browser
ENV CHROME_PATH=/usr/lib/chromium/
ENV MEMORY_CACHE=0

# install chromium, tini and clear cache
RUN apk add --update-cache chromium tini \
&& rm -rf /var/cache/apk/* /tmp/*
RUN apk add --no-cache chromium tini

USER node
WORKDIR "/home/node"

COPY ./package.json .
COPY ./server.js .

# install npm packages
RUN npm install --no-package-lock

COPY ./utils ./utils
gowrizrh marked this conversation as resolved.
Show resolved Hide resolved
COPY ./server.js .

EXPOSE 3000

HEALTHCHECK CMD netstat -ltn | grep -c 3000
Expand Down
1 change: 1 addition & 0 deletions packages/prerender-fargate/lib/prerender/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"start": "node server.js"
},
"dependencies": {
"pino": "^9.1.0",
"prerender": "5.20.0",
"prerender-aws-s3-cache": "1.0.1"
}
Expand Down
68 changes: 58 additions & 10 deletions packages/prerender-fargate/lib/prerender/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,59 @@
'use strict';

const prerender = require('prerender');
const util = require('prerender/lib/util');
const crypto = require('crypto');
const s3Cache = require('prerender-aws-s3-cache');
const logger = require('./utils/logger')

/**
* Replace prerender's util log function with our own which uses pino to log
*
* @param {...any} args
* @returns
*/
util.log = function (...args) {
if (process.env.DISABLE_LOGGING) {
return;
}

logger.info(args.join(' '));
};

const server = prerender({
chromeFlags: ['--no-sandbox', '--headless', '--disable-gpu', '--disable-web-security', '--remote-debugging-port=9222', '--hide-scrollbars', '--disable-dev-shm-usage'],
forwardHeaders: true,
chromeLocation: '/usr/bin/chromium-browser'
});

// Healthcheck endpoint
server.use({
beforeSend: (req, res, next) => {
if (req.prerender.url === "health") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh wait nvm, this is good now 😄

return res.send(200, 'OK');
}

return next();
}
});

server.use({
beforeSend: (req, res, next) => {
const ms = new Date().getTime() - req.prerender.start.getTime();

logger.render({
time: ms,
path: req.prerender.url,
status: req.prerender.statusCode,
ip: req.socket.remoteAddress,
headers: req.prerender.headers,
origin: req.headers
});

return next();
},
});

const tokenJson = JSON.parse(process.env.TOKEN_SECRET);
const tokens = Object.keys(tokenJson);

Expand All @@ -31,10 +75,12 @@ server.use({
// Log "x-prerender-user-agent" value forwarded from CloudFront/Lambda@edge that contains the original User-Agent value. If not present, e.g. requests from ELB, default to "user-agent" value.
const userAgent = req.get('x-prerender-user-agent') || req.get('user-agent');

console.log(`${new Date().toISOString()} User-Agent: "${userAgent}" ${req.prerender.reqId} ${req.prerender.url}`);
logger.info(`${new Date().toISOString()} User-Agent: "${userAgent}" ${req.prerender.reqId} ${req.prerender.url}`)
let auth = req.headers['x-prerender-token'];

if (!auth) {
console.log(`${new Date().toISOString()} "${userAgent}" ${req.prerender.reqId} Authentication header not found.`);
logger.info(`${new Date().toISOString()} "${userAgent}" ${req.prerender.reqId} Authentication header not found.`);

return res.send(401);
}

Expand All @@ -49,7 +95,7 @@ server.use({
if (authenticated) break;
}
if (!authenticated) {
console.log(`${new Date().toISOString()} "${userAgent}" ${req.prerender.reqId} Authentication Failed.`);
logger.info(`${new Date().toISOString()} "${userAgent}" ${req.prerender.reqId} Authentication Failed.`);
return res.send(401);
}

Expand Down Expand Up @@ -82,14 +128,15 @@ server.use({
requestReceived: function(req, res, next) {
const fetchCachedObject = function (err, result) {
if (!err && result) {
console.log(`Found cached object: ${key}`);
logger.info(`Found cached object: ${key}`);

if (result.Metadata.location){
res.setHeader('Location', result.Metadata.location);
}
// default 200 for legacy objects that do not have Metadata.httpreturncode defined
return res.send(result.Metadata.httpreturncode || 200, result.Body);
} else {
console.error(`Fetching cached object from S3 bucket failed with error: ${err.code}`);
logger.error(`Fetching cached object from S3 bucket failed with error: ${err.code}`);
}
next();
}
Expand Down Expand Up @@ -117,21 +164,22 @@ server.use({
var s3Metadata = {}
const cacheObject = function (err, result) {
if (!err && result) {
console.log(`Cached object ${key} already present. Skipping caching...`);
logger.info(`Cached object ${key} already present. Skipping caching...`);
} else {
console.log(`Caching the object ${req.prerender.url} with statusCode ${req.prerender.statusCode}`);
logger.info(`Caching the object ${req.prerender.url} with statusCode ${req.prerender.statusCode}`);
s3.putObject({
Key: key,
ContentType: 'text/html;charset=UTF-8',
StorageClass: 'REDUCED_REDUNDANCY',
Body: req.prerender.content,
Metadata: s3Metadata
}, function(err, result) {
console.log(result);
if (err) console.error(err);
logger.info(result);
if (err) logger.error(err);
});
}
}

// Inspect prerender meta tags and update response accordingly
if (req.prerender.content && req.prerender.renderType == 'html') {
const statusMatchRegex = /<meta[^<>]*(?:name=['"]prerender-status-code['"][^<>]*content=['"]([0-9]{3})['"]|content=['"]([0-9]{3})['"][^<>]*name=['"]prerender-status-code['"])[^<>]*>/i;
Expand Down Expand Up @@ -165,7 +213,7 @@ server.use({
}, cacheObject);
} else {
// Skip caching for the http response codes not in the list, such as 404
console.log(`StatusCode ${req.prerender.statusCode} for ${req.prerender.url} is not in the cachable code list. Returning without caching the result.`);
logger.info(`StatusCode ${req.prerender.statusCode} for ${req.prerender.url} is not in the cachable code list. Returning without caching the result.`);
}

next();
Expand Down
20 changes: 20 additions & 0 deletions packages/prerender-fargate/lib/prerender/utils/logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"use strict";

const pino = require("pino");

module.exports = pino({
base: undefined,
timestamp: false,
messageKey: "message",
customLevels: {
render: 35,
},
level: process.env.LOG_LEVEL || "info",
formatters: {
level: label => {
return {
level: label,
};
},
},
});
Loading