Skip to content

Commit 5f7525a

Browse files
authored
Merge pull request #130 from fensak-io/main
Release
2 parents 446ba93 + 574dae3 commit 5f7525a

File tree

12 files changed

+170
-37
lines changed

12 files changed

+170
-37
lines changed

config/custom-environment-variables.json5

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@
4545
host: "FENSAK_LOGGING_LOKI_HOST",
4646
basicAuth: "FENSAK_LOGGING_LOKI_BASIC_AUTH",
4747
},
48+
sentry: {
49+
enabled: {
50+
__name: "FENSAK_LOGGING_SENTRY_ENABLED",
51+
__format: "boolean",
52+
},
53+
dsn: "FENSAK_LOGGING_SENTRY_DSN",
54+
},
4855
},
4956
github: {
5057
allowedOrgs: {

config/default.json5

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,16 @@
6060

6161
// Basic authentication credentials to access the Loki instance.
6262
basicAuth: "",
63-
}
63+
},
64+
65+
// Settings/Secrets for configuring Sentry for error reporting.
66+
sentry: {
67+
// Whether Sentry for error reporting should be enabled.
68+
enabled: false,
69+
70+
// The DSN for the project to report errors to.
71+
dsn: "",
72+
},
6473
},
6574

6675
/**

deno.lock

Lines changed: 67 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

deployments/release/integration_test.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -537,8 +537,9 @@ Deno.test("passed required rule and failed automerge requires review", async (t)
537537
});
538538

539539
/**
540-
* Wait for the Fensak Staging check to show up on the head commit of the given branch. This will timeout after 1
541-
* minute.
540+
* Wait for the Fensak Staging check to show up on the head commit of the given branch. This will timeout after
541+
* 3 minutes. 3 minutes feels very long, but unfortunately sometimes GitHub has significant delays in the webhooks so it
542+
* makes sense to wait that long.
542543
*/
543544
async function waitForFensakStagingCheck(
544545
octokit: Octokit,
@@ -548,7 +549,7 @@ async function waitForFensakStagingCheck(
548549
previousCheckRuns?: number[],
549550
): Promise<GitHubCheckRun> {
550551
const maxRetries = 60;
551-
const sleepBetweenRetries = 1000;
552+
const sleepBetweenRetries = 3000;
552553

553554
const headSHA = await getHeadSHA(octokit, owner, repoName, branchName);
554555
for (let i = 0; i < maxRetries; i++) {

deps.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ export {
5858
babelPresetTypescript,
5959
config,
6060
};
61+
62+
import * as Sentry from "npm:@sentry/node@^7.74.1";
63+
export { Sentry };
64+
6165
// Must use esm.sh version for auth-app. See https://github.com/octokit/auth-app.js/issues/465
6266
export { createAppAuth as octokitCreateAppAuth } from "https://esm.sh/@octokit/[email protected]";
6367
// Must use esm.sh version for auth-oauth-app. See https://github.com/octokit/auth-app.js/issues/465

logging/logger.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ import { config, winston, WinstonLoki, WinstonTransport } from "../deps.ts";
55

66
const serviceEnv = config.get("env");
77
const loggingLevel = config.get("logging.level");
8+
const sentryEnabled = config.get("logging.sentry.enabled");
89
const lokiEnabled = config.get("logging.loki.enabled");
910
const lokiHost = config.get("logging.loki.host");
1011
const lokiAuth = config.get("logging.loki.basicAuth");
12+
1113
export let lokiTransport: WinstonLoki;
1214
if (lokiEnabled) {
1315
lokiTransport = new WinstonLoki({
@@ -31,6 +33,9 @@ export function logConfig(): void {
3133
if (lokiEnabled) {
3234
logger.info(`Shipping logs to Loki host: ${lokiHost}`);
3335
}
36+
if (sentryEnabled) {
37+
logger.info(`Reporting errors to Sentry`);
38+
}
3439

3540
const repoLimits = config.get("planRepoLimits");
3641
logger.info("planRepoLimits:");

middlewares/mod.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@
77
*/
88
export * from "./ghevent.ts";
99
export * from "./mgmt.ts";
10+
export * from "./sentry.ts";

middlewares/sentry.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (c) Fensak, LLC.
2+
// SPDX-License-Identifier: AGPL-3.0-or-later OR BUSL-1.1
3+
4+
import { config, Context, Sentry } from "../deps.ts";
5+
import type { Middleware, Next } from "../deps.ts";
6+
7+
const appEnv = config.get("env");
8+
const sentryEnabled = config.get("logging.sentry.enabled");
9+
const sentryDSN = config.get("logging.sentry.dsn");
10+
11+
if (sentryEnabled) {
12+
Sentry.init({
13+
dsn: sentryDSN,
14+
environment: appEnv,
15+
});
16+
}
17+
18+
export const sentryReportError: Middleware = async (
19+
_ctx: Context,
20+
next: Next,
21+
): Promise<void> => {
22+
try {
23+
await next();
24+
} catch (e) {
25+
Sentry.captureException(e);
26+
throw e;
27+
}
28+
};

web/app.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
import { Application, basemiddlewares, config, Router } from "../deps.ts";
55

66
import { logger } from "../logging/mod.ts";
7+
import {
8+
sentryReportError as sentryReportErrorMiddleware,
9+
} from "../middlewares/mod.ts";
710

811
import { attachRoutes } from "./routes.ts";
912
import { attachMgmtAPIRoutes } from "./mgmt_routes.ts";
@@ -15,6 +18,7 @@ export async function startWebServer(): Promise<void> {
1518

1619
app.use(basemiddlewares.newLoggerMiddleware(logger));
1720
app.use(basemiddlewares.newErrorMiddleware(logger));
21+
app.use(sentryReportErrorMiddleware);
1822
app.use(basemiddlewares.timing);
1923
app.use(basemiddlewares.requestId);
2024
app.use(basemiddlewares.unsupportedRoute);

web/mgmt_routes.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,17 @@ import {
1010
handleSubscriptionEvent,
1111
} from "../mgmt/mod.ts";
1212
import {
13+
enqueueMsg,
1314
FensakConfigSource,
1415
getComputedFensakConfig,
1516
getSubscription,
17+
MessageType,
1618
mustGetGitHubOrgWithSubscription,
19+
waitForHealthCheckResult,
1720
} from "../svcdata/mod.ts";
1821
import type { GitHubOrgWithSubscription } from "../svcdata/mod.ts";
1922
import { isOrgManager } from "../ghstd/mod.ts";
23+
import { getRandomString } from "../xtd/mod.ts";
2024

2125
interface APIOrganization {
2226
slug: string;
@@ -38,6 +42,8 @@ export function attachMgmtAPIRoutes(router: Router): void {
3842
const corsMW = oakCors({ origin: corsOrigins });
3943

4044
router
45+
.get("/healthz", healthCheck)
46+
.get("/sentry-test", testSentry)
4147
.post(
4248
"/hooks/mgmt",
4349
middlewares.assertMgmtEvent,
@@ -59,6 +65,35 @@ export function attachMgmtAPIRoutes(router: Router): void {
5965
);
6066
}
6167

68+
async function healthCheck(ctx: Context): Promise<void> {
69+
const requestID = getRandomString(6);
70+
await enqueueMsg({
71+
type: MessageType.HealthCheck,
72+
payload: {
73+
requestID: requestID,
74+
},
75+
});
76+
const result = await waitForHealthCheckResult(requestID);
77+
if (!result) {
78+
ctx.response.status = Status.InternalServerError;
79+
ctx.response.body = {
80+
status: Status.InternalServerError,
81+
msg: "timed out waiting for worker health result",
82+
};
83+
return;
84+
}
85+
86+
ctx.response.status = Status.OK;
87+
ctx.response.body = {
88+
status: Status.OK,
89+
msg: "system ok",
90+
};
91+
}
92+
93+
function testSentry(_ctx: Context): void {
94+
throw new Error("Test error to ensure sentry is working");
95+
}
96+
6297
async function handleGetOrganizations(ctx: Context): Promise<void> {
6398
const token = ctx.state.apiToken;
6499
const octokit = new Octokit({ auth: token });

0 commit comments

Comments
 (0)