Skip to content

Commit

Permalink
feat: add Workers observability settings (#6668)
Browse files Browse the repository at this point in the history
Adds a new `observability` setting for wrangler.toml to enable automatic observability for Workers.
  • Loading branch information
zebp authored Sep 12, 2024
1 parent 59a0072 commit 88c40be
Show file tree
Hide file tree
Showing 18 changed files with 286 additions and 83 deletions.
7 changes: 7 additions & 0 deletions .changeset/chilled-seals-appear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"wrangler": minor
---

feature: add observability setting to wrangler.toml

Adds the `observability` setting which provides your Worker with automatic persistent logs that can be searched, filtered, and queried directly from the Workers dashboard.
185 changes: 124 additions & 61 deletions packages/wrangler/src/__tests__/configuration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1053,6 +1053,10 @@ describe("normalizeAndValidateConfig()", () => {
placement: {
mode: "smart",
},
observability: {
enabled: true,
head_sampling_rate: 1,
},
};

const { config, diagnostics } = normalizeAndValidateConfig(
Expand Down Expand Up @@ -1131,6 +1135,10 @@ describe("normalizeAndValidateConfig()", () => {
placement: {
mode: "INVALID",
},
observability: {
enabled: "INVALID",
head_sampling_rate: "INVALID",
},
} as unknown as RawEnvironment;

const { config, diagnostics } = normalizeAndValidateConfig(
Expand All @@ -1142,67 +1150,69 @@ describe("normalizeAndValidateConfig()", () => {
expect(config).toEqual(expect.objectContaining(expectedConfig));
expect(diagnostics.hasWarnings()).toBe(false);
expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
"Processing wrangler configuration:
- Expected \\"route\\" to be either a string, or an object with shape { pattern, custom_domain, zone_id | zone_name }, but got 888.
- Expected \\"account_id\\" to be of type string but got 222.
- Expected \\"routes\\" to be an array of either strings or objects with the shape { pattern, custom_domain, zone_id | zone_name }, but these weren't valid: [
666,
777,
{
\\"pattern\\": 123,
\\"zone_id\\": \\"zone_id_1\\"
},
{
\\"pattern\\": \\"route_2\\",
\\"zone_id\\": 123
},
{
\\"pattern\\": \\"route_2\\",
\\"zone_name\\": 123
},
{
\\"pattern\\": \\"route_3\\"
},
{
\\"zone_id\\": \\"zone_id_4\\"
},
{
\\"zone_name\\": \\"zone_name_4\\"
},
{},
{
\\"pattern\\": \\"route_5\\",
\\"zone_id\\": \\"zone_id_5\\",
\\"some_other_key\\": 123
},
{
\\"pattern\\": \\"route_5\\",
\\"zone_name\\": \\"zone_name_5\\",
\\"some_other_key\\": 123
}
].
- Expected exactly one of the following fields [\\"routes\\",\\"route\\"].
- Expected \\"workers_dev\\" to be of type boolean but got \\"BAD\\".
- Expected \\"build.command\\" to be of type string but got 1444.
- Expected \\"build.cwd\\" to be of type string but got 1555.
- Expected \\"build.watch_dir\\" to be of type string but got 1666.
- Expected \\"compatibility_date\\" to be of type string but got 333.
- Expected \\"compatibility_flags\\" to be of type string array but got [444,555].
- Expected \\"jsx_factory\\" to be of type string but got 999.
- Expected \\"jsx_fragment\\" to be of type string but got 1000.
- Expected \\"tsconfig\\" to be of type string but got true.
- Expected \\"name\\" to be of type string, alphanumeric and lowercase with dashes only but got 111.
- Expected \\"main\\" to be of type string but got 1333.
- Expected \\"usage_model\\" field to be one of [\\"bundled\\",\\"unbound\\"] but got \\"INVALID\\".
- Expected \\"placement.mode\\" field to be one of [\\"off\\",\\"smart\\"] but got \\"INVALID\\".
- The field \\"define.DEF1\\" should be a string but got 1777.
- Expected \\"no_bundle\\" to be of type boolean but got \\"INVALID\\".
- Expected \\"minify\\" to be of type boolean but got \\"INVALID\\".
- Expected \\"node_compat\\" to be of type boolean but got \\"INVALID\\".
- Expected \\"first_party_worker\\" to be of type boolean but got \\"INVALID\\".
- Expected \\"logpush\\" to be of type boolean but got \\"INVALID\\".
- Expected \\"upload_source_maps\\" to be of type boolean but got \\"INVALID\\"."
`);
"Processing wrangler configuration:
- Expected \\"route\\" to be either a string, or an object with shape { pattern, custom_domain, zone_id | zone_name }, but got 888.
- Expected \\"account_id\\" to be of type string but got 222.
- Expected \\"routes\\" to be an array of either strings or objects with the shape { pattern, custom_domain, zone_id | zone_name }, but these weren't valid: [
666,
777,
{
\\"pattern\\": 123,
\\"zone_id\\": \\"zone_id_1\\"
},
{
\\"pattern\\": \\"route_2\\",
\\"zone_id\\": 123
},
{
\\"pattern\\": \\"route_2\\",
\\"zone_name\\": 123
},
{
\\"pattern\\": \\"route_3\\"
},
{
\\"zone_id\\": \\"zone_id_4\\"
},
{
\\"zone_name\\": \\"zone_name_4\\"
},
{},
{
\\"pattern\\": \\"route_5\\",
\\"zone_id\\": \\"zone_id_5\\",
\\"some_other_key\\": 123
},
{
\\"pattern\\": \\"route_5\\",
\\"zone_name\\": \\"zone_name_5\\",
\\"some_other_key\\": 123
}
].
- Expected exactly one of the following fields [\\"routes\\",\\"route\\"].
- Expected \\"workers_dev\\" to be of type boolean but got \\"BAD\\".
- Expected \\"build.command\\" to be of type string but got 1444.
- Expected \\"build.cwd\\" to be of type string but got 1555.
- Expected \\"build.watch_dir\\" to be of type string but got 1666.
- Expected \\"compatibility_date\\" to be of type string but got 333.
- Expected \\"compatibility_flags\\" to be of type string array but got [444,555].
- Expected \\"jsx_factory\\" to be of type string but got 999.
- Expected \\"jsx_fragment\\" to be of type string but got 1000.
- Expected \\"tsconfig\\" to be of type string but got true.
- Expected \\"name\\" to be of type string, alphanumeric and lowercase with dashes only but got 111.
- Expected \\"main\\" to be of type string but got 1333.
- Expected \\"usage_model\\" field to be one of [\\"bundled\\",\\"unbound\\"] but got \\"INVALID\\".
- Expected \\"placement.mode\\" field to be one of [\\"off\\",\\"smart\\"] but got \\"INVALID\\".
- The field \\"define.DEF1\\" should be a string but got 1777.
- Expected \\"no_bundle\\" to be of type boolean but got \\"INVALID\\".
- Expected \\"minify\\" to be of type boolean but got \\"INVALID\\".
- Expected \\"node_compat\\" to be of type boolean but got \\"INVALID\\".
- Expected \\"first_party_worker\\" to be of type boolean but got \\"INVALID\\".
- Expected \\"logpush\\" to be of type boolean but got \\"INVALID\\".
- Expected \\"upload_source_maps\\" to be of type boolean but got \\"INVALID\\".
- Expected \\"observability.enabled\\" to be of type boolean but got \\"INVALID\\".
- Expected \\"observability.head_sampling_rate\\" to be of type number but got \\"INVALID\\"."
`);
});

describe("name", () => {
Expand Down Expand Up @@ -3795,6 +3805,10 @@ describe("normalizeAndValidateConfig()", () => {
first_party_worker: true,
logpush: true,
upload_source_maps: true,
observability: {
enabled: true,
head_sampling_rate: 0.5,
},
};

const { config, diagnostics } = normalizeAndValidateConfig(
Expand Down Expand Up @@ -3841,6 +3855,9 @@ describe("normalizeAndValidateConfig()", () => {
first_party_worker: false,
logpush: false,
upload_source_maps: false,
observability: {
enabled: false,
},
};
const rawConfig: RawConfig = {
name: "mock-name",
Expand All @@ -3866,6 +3883,9 @@ describe("normalizeAndValidateConfig()", () => {
first_party_worker: true,
logpush: true,
upload_source_maps: true,
observability: {
enabled: true,
},
env: {
ENV1: rawEnv,
},
Expand Down Expand Up @@ -5464,6 +5484,49 @@ describe("normalizeAndValidateConfig()", () => {
});
});

describe("[observability]", () => {
it("should error on invalid observability", () => {
const { diagnostics } = normalizeAndValidateConfig(
{
observability: {
notEnabled: "true",
head_sampling_rate: true,
},
} as unknown as RawConfig,
undefined,
{ env: undefined }
);

expect(diagnostics.hasWarnings()).toBe(false);
expect(diagnostics.hasErrors()).toBe(true);
expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
"Processing wrangler configuration:
- \\"observability.enabled\\" is a required field.
- Expected \\"observability.head_sampling_rate\\" to be of type number but got true."
`);
});

it("should error on a sampling rate out of range", () => {
const { diagnostics } = normalizeAndValidateConfig(
{
observability: {
enabled: true,
head_sampling_rate: 2,
},
} satisfies RawConfig,
undefined,
{ env: undefined }
);

expect(diagnostics.hasWarnings()).toBe(false);
expect(diagnostics.hasErrors()).toBe(true);
expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
"Processing wrangler configuration:
- \`observability.head_sampling_rate\` must be a value between 0 and 1."
`);
});
});

describe("(deprecated)", () => {
it("should remove and warn about deprecated properties", () => {
const environment: RawEnvironment = {
Expand Down
29 changes: 29 additions & 0 deletions packages/wrangler/src/__tests__/deploy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10758,6 +10758,35 @@ export default{
`);
});
});

describe("[observability]", () => {
it("should allow uploading workers with observability", async () => {
writeWranglerToml({
observability: {
enabled: true,
head_sampling_rate: 0.5,
},
});
await fs.promises.writeFile("index.js", `export default {};`);
mockSubDomainRequest();
mockUploadWorkerRequest({
expectedObservability: {
enabled: true,
head_sampling_rate: 0.5,
},
});

await runWrangler("publish index.js");
expect(std.out).toMatchInlineSnapshot(`
"Total Upload: xx KiB / gzip: xx KiB
Worker Startup Time: 100 ms
Uploaded test-name (TIMINGS)
Deployed test-name triggers (TIMINGS)
https://test-name.test-sub-domain.workers.dev
Current Version ID: Galaxy-Class"
`);
});
});
});

/** Write mock assets to the file system so they can be uploaded. */
Expand Down
5 changes: 5 additions & 0 deletions packages/wrangler/src/__tests__/helpers/mock-upload-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export function mockUploadWorkerRequest(
expectedScriptName?: string;
expectedExperimentalAssets?: boolean;
useOldUploadApi?: boolean;
expectedObservability?: CfWorkerInit["observability"];
} = {}
) {
const expectedScriptName = (options.expectedScriptName ??= "test-name");
Expand Down Expand Up @@ -111,6 +112,9 @@ export function mockUploadWorkerRequest(
config: {},
});
}
if ("expectedObservability" in options) {
expect(metadata.observability).toEqual(expectedObservability);
}
if (expectedUnsafeMetaData !== undefined) {
Object.keys(expectedUnsafeMetaData).forEach((key) => {
expect(metadata[key]).toEqual(expectedUnsafeMetaData[key]);
Expand Down Expand Up @@ -168,6 +172,7 @@ export function mockUploadWorkerRequest(
keepSecrets,
expectedDispatchNamespace,
useOldUploadApi,
expectedObservability,
} = options;
if (env && !legacyEnv) {
msw.use(
Expand Down
50 changes: 32 additions & 18 deletions packages/wrangler/src/__tests__/init.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2611,6 +2611,7 @@ describe("init", () => {
limits,
compatibility_date,
tail_consumers: [{ service: "listener" }],
observability: { enabled: true, head_sampling_rate: 0.5 },
},
},
created_on: "1987-09-27",
Expand Down Expand Up @@ -2747,6 +2748,7 @@ describe("init", () => {
],
},
tail_consumers: [{ service: "listener" }],
observability: { enabled: true, head_sampling_rate: 0.5 },
};

function mockSupportingDashRequests(expectedAccountId: string) {
Expand Down Expand Up @@ -3041,24 +3043,28 @@ describe("init", () => {
expect(
fs.readFileSync("./isolinear-optical-chip/wrangler.toml", "utf8")
).toMatchInlineSnapshot(`
"name = \\"isolinear-optical-chip\\"
main = \\"src/index.js\\"
compatibility_date = \\"1987-09-27\\"
workers_dev = false
[[routes]]
pattern = \\"delta.quadrant\\"
zone_name = \\"delta.quadrant\\"
[[routes]]
pattern = \\"random.host.name\\"
zone_name = \\"some-zone-name\\"
custom_domain = true
[[tail_consumers]]
service = \\"listener\\"
"
`);
"name = \\"isolinear-optical-chip\\"
main = \\"src/index.js\\"
compatibility_date = \\"1987-09-27\\"
workers_dev = false
[[routes]]
pattern = \\"delta.quadrant\\"
zone_name = \\"delta.quadrant\\"
[[routes]]
pattern = \\"random.host.name\\"
zone_name = \\"some-zone-name\\"
custom_domain = true
[[tail_consumers]]
service = \\"listener\\"
[observability]
enabled = true
head_sampling_rate = 0.5
"
`);
});

it("should download source script from dashboard w/ positional <name> in TypeScript project", async () => {
Expand Down Expand Up @@ -3176,6 +3182,10 @@ describe("init", () => {
[[tail_consumers]]
service = \\"listener\\"
[observability]
enabled = true
head_sampling_rate = 0.5
[vars]
ANOTHER-NAME = \\"thing-TEXT\\"
Expand Down Expand Up @@ -3456,6 +3466,10 @@ describe("init", () => {
workers_dev: true,
name: "isolinear-optical-chip",
tail_consumers: [{ service: "listener" }],
observability: {
enabled: true,
head_sampling_rate: 0.5,
},
}),
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ function createWorkerBundleFormData(
tail_consumers: undefined,
limits: config?.limits,
experimental_assets: undefined,
observability: undefined,
};

return createWorkerUploadForm(worker);
Expand Down
Loading

0 comments on commit 88c40be

Please sign in to comment.