Skip to content

Commit 3fea1d3

Browse files
Logger context (#1073)
* Basic implementation * more tests and docs
1 parent 3c53849 commit 3fea1d3

File tree

6 files changed

+54
-10
lines changed

6 files changed

+54
-10
lines changed

docs/extending-turnilo.md

+23-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,28 @@ Turnilo lets you extend its behaviour in three ways:
1212
* Query decorator for all Plywood queries sent to Druid cluster
1313
* Plugins for backend application
1414

15+
## turniloMetadata
16+
17+
Turnilo adds `turniloMetadata` object to every `Request` object.
18+
It is a namespace for you to keep any values necessary that live with requests.
19+
20+
`turniloMetadata` has special properties:
21+
22+
### `loggerContext`
23+
24+
It is a `Record` of values that will be added by logger for every message.
25+
26+
You could use it to log User Agent of browser that requested view with a simple [plugin](#plugins):
27+
28+
```javascript
29+
app.use(function(req, res, next) {
30+
req.turniloMetadata.loggerContext.userAgent = req.get('User-Agent');
31+
next();
32+
});
33+
```
34+
35+
36+
1537
## Request decorator
1638

1739
In the cluster config add a key `druidRequestDecorator` with property `path` that points to a relative js file.
@@ -131,5 +153,4 @@ This function will be called at the start of application with following paramete
131153
Worth to look into !(express documentation)[https://expressjs.com/en/api.html#app].
132154
Use `get`, `post` etc. to define new endpoints. Use `use` to define middleware.
133155

134-
Additionally, Turnilo defines empty object on Request object under `turniloMetadata` key.
135-
Here you can pass values between your plugins and not pollute headers.
156+
Use [`turniloMetadata`](#turniloMetadata) object on `Request` to pass values between your plugins and not pollute headers.

src/server/app.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ import { errorLayout } from "./views";
3838

3939
declare module "express" {
4040
export interface Request {
41-
turniloMetadata: object;
41+
turniloMetadata: {
42+
loggerContext: Record<string, unknown>
43+
};
4244
}
4345
}
4446

@@ -94,7 +96,9 @@ export default function createApp(serverSettings: ServerSettings, settingsManage
9496
}
9597

9698
app.use((req: Request, res: Response, next: Function) => {
97-
req.turniloMetadata = {};
99+
req.turniloMetadata = {
100+
loggerContext: {}
101+
};
98102
next();
99103
});
100104

src/server/routes/query/query.mocha.ts

+7
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ const app = express();
4747

4848
app.use(bodyParser.json());
4949

50+
app.use((req: any, res, next) => {
51+
req.turniloMetadata = {
52+
loggerContext: {}
53+
};
54+
next();
55+
});
56+
5057
app.use("/", queryRouter(settingsManagerFixture));
5158

5259
describe("query router", () => {

src/server/routes/query/routes/visualization.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ function getQuery(essence: Essence, timekeeper: Timekeeper): Expression {
2828
return essence.visualization.name === "grid" ? makeGridQuery(essence, timekeeper) : makeQuery(essence, timekeeper);
2929
}
3030

31-
export default async function visualizationRoute({ context }: QueryRouterRequest, res: Response) {
31+
export default async function visualizationRoute({ turniloMetadata, context }: QueryRouterRequest, res: Response) {
3232
const { dataCube, essence, decorator, timekeeper, logger } = context;
3333
const query = getQuery(essence, timekeeper);
3434
const queryTimeStart = Date.now();
3535
const result = await executeQuery(dataCube, query, essence.timezone, decorator);
36-
logQueryInfo(essence, timekeeper, logger.setLoggerId("turnilo-visualization-query"), Date.now() - queryTimeStart);
36+
logQueryInfo(essence, timekeeper, logger.setLoggerId("turnilo-visualization-query"), Date.now() - queryTimeStart, turniloMetadata.loggerContext);
3737
res.json({ result });
3838
}

src/server/utils/query/log-query.mocha.ts

+14-3
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ describe("log-query-info", () => {
5050
};
5151

5252
it("Should log all basic variables", () => {
53-
logQueryInfo(baseEssence, timekeeper, logger, executionTime);
53+
logQueryInfo(baseEssence, timekeeper, logger, executionTime, {});
5454
expect(logger.log.calledWith(
5555
expectedMessage,
5656
expectedBasicVariables
@@ -59,7 +59,7 @@ describe("log-query-info", () => {
5959

6060
it("Should log additional time shift variables", () => {
6161
const essence = baseEssence.set("timeShift", TimeShift.fromJS("P1D"));
62-
logQueryInfo(essence, timekeeper, logger, executionTime);
62+
logQueryInfo(essence, timekeeper, logger, executionTime, {});
6363
expect(logger.log.calledWith(
6464
expectedMessage,
6565
{
@@ -73,7 +73,7 @@ describe("log-query-info", () => {
7373

7474
it("Should log additional time split variables", () => {
7575
const essence = baseEssence.addSplit(timeSplitCombine("time", "P2D"), VisStrategy.FairGame);
76-
logQueryInfo(essence, timekeeper, logger, executionTime);
76+
logQueryInfo(essence, timekeeper, logger, executionTime, {});
7777
expect(logger.log.calledWith(
7878
expectedMessage,
7979
{
@@ -85,4 +85,15 @@ describe("log-query-info", () => {
8585
)).to.be.true;
8686
});
8787

88+
it("Should log additional logger context", () => {
89+
logQueryInfo(baseEssence, timekeeper, logger, executionTime, { contextName: "context-value" });
90+
expect(logger.log.calledWith(
91+
expectedMessage,
92+
{
93+
...expectedBasicVariables,
94+
contextName: "context-value"
95+
}
96+
)).to.be.true;
97+
});
98+
8899
});

src/server/utils/query/log-query.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,11 @@ function timeVariables(essence: Essence, timekeeper: Timekeeper): Record<string,
6565
return variables;
6666
}
6767

68-
export function logQueryInfo(essence: Essence, timekeeper: Timekeeper, logger: Logger, executionTime: number) {
68+
export function logQueryInfo(essence: Essence, timekeeper: Timekeeper, logger: Logger, executionTime: number, context: Record<string, unknown>) {
6969
const nonTimeFilters = essence.filter.removeClause(essence.getTimeDimension().name);
7070

7171
logger.log(`Visualization query ${essence.description(timekeeper)}`, {
72+
...context,
7273
executionTime,
7374
...timeVariables(essence, timekeeper),
7475
dataCube: essence.dataCube.name,

0 commit comments

Comments
 (0)