diff --git a/apps/landing/src/pages/guides/dynatrace-pricing.astro b/apps/landing/src/pages/guides/dynatrace-pricing.astro index ed4e2e1fe4..0ede725e72 100644 --- a/apps/landing/src/pages/guides/dynatrace-pricing.astro +++ b/apps/landing/src/pages/guides/dynatrace-pricing.astro @@ -255,14 +255,26 @@ const articleJsonLd = {
+
+

+ You want to know what Dynatrace will cost, and the pricing page lists unit prices instead of a total. Dynatrace is a full-stack monitoring platform: an agent on each server watches your applications, the servers themselves and your users' browsers, and reports problems in one place. Dynatrace pricing is pay-as-you-use against a yearly minimum: every host-hour, gigabyte and user session is metered and taken out of an amount you commit to each year. The rate card is public but the minimum isn't, so an estimate built from the rate card alone can come in under the contract you're asked to sign. By the end you can price your own fleet from the rate card and know what to ask sales. +

+
+

Key takeaways

+
    +
  • Full-Stack Monitoring is $0.01 per memory-GiB-hour with a 4 GiB minimum: $58.40 a month for an 8 GiB host.
  • +
  • Infrastructure Monitoring is $0.04 per host-hour for any size host, $29.20 a month.
  • +
  • Logs and traces cost $0.20 per GiB to ingest, plus separate charges to retain and query them.
  • +
  • No per-seat fees: every user gets the full platform.
  • +
  • Everything draws from an annual commitment whose minimum Dynatrace doesn't publish.
  • +
+
+
+

01 · The model

How Dynatrace pricing works

-
-

Dynatrace pricing is pay-as-you-use against a yearly minimum. You agree to spend at least a set amount each year, and everything you monitor is metered by the hour or by the gigabyte and taken out of that amount.

-
-

The contract is the Dynatrace Platform Subscription (DPS). It includes every generally available capability, so there are no modules to buy, and it has no per-seat fees: every user gets the full platform. What you pay depends on three kinds of meter, and this guide colors each one the same way throughout:

@@ -571,14 +583,15 @@ const articleJsonLd = { .dt-guide h2 { margin: 0 0 1.5rem; font-family: var(--font-display); font-size: clamp(1.75rem, 4vw, 2.5rem); font-weight: 500; line-height: 1.08; letter-spacing: -0.03em; color: var(--foreground); text-wrap: balance; } .dt-guide h3 { display: flex; align-items: center; gap: 0.6rem; margin: 3rem 0 0.8rem; font-family: var(--font-display); font-size: 1.2rem; font-weight: 550; line-height: 1.3; letter-spacing: -0.015em; color: var(--foreground); } .dt-guide h4 { margin: 0; font-family: var(--font-display); font-size: 0.95rem; font-weight: 550; color: var(--foreground); } - .dt-guide > section > p:not(.guide-eyebrow, .guide-kicker, .guide-caption), .dt-guide .guide-answer p, .dt-guide .guide-list li { margin: 0 0 1.15rem; font-size: 17px; line-height: 1.7; font-weight: 430; color: color-mix(in oklab, var(--foreground) 85%, var(--background)); } + .dt-guide > section > p:not(.guide-eyebrow, .guide-kicker, .guide-caption), .dt-guide .guide-list li { margin: 0 0 1.15rem; font-size: 17px; line-height: 1.7; font-weight: 430; color: color-mix(in oklab, var(--foreground) 85%, var(--background)); } .dt-guide strong { font-weight: 600; color: var(--foreground); } .dt-guide code:not(pre code) { border: 1px solid var(--border); background: var(--bg-elevated); padding: 0.1rem 0.35rem; font-family: var(--font-mono); font-size: 12px; color: var(--foreground); } .dt-guide pre { margin: 1.25rem 0 1.5rem; overflow-x: auto; border: 1px solid var(--border); border-radius: 0.5rem; background: var(--bg-deep); padding: 0.9rem 1.1rem; font-family: var(--font-mono); font-size: 12px; line-height: 1.75; color: var(--foreground); } .dt-guide a:not(.guide-button) { color: var(--primary); text-decoration: underline; text-decoration-color: color-mix(in oklab, var(--primary) 42%, transparent); text-underline-offset: 3px; transition: color 150ms ease; } .dt-guide a:not(.guide-button):hover { color: var(--foreground); } - .dt-guide .guide-answer { margin: 2rem 0; border-left: 2px solid var(--primary); border-radius: 0 0.5rem 0.5rem 0; background: color-mix(in oklab, var(--primary) 8%, var(--bg-deep)); padding: 1.25rem 1.35rem; } - .dt-guide .guide-answer p { margin: 0; font-size: 16px; line-height: 1.7; color: var(--foreground); } + .dt-guide .guide-takeaways { margin: 2rem 0 0; border-left: 2px solid var(--primary); border-radius: 0 0.5rem 0.5rem 0; background: color-mix(in oklab, var(--primary) 8%, var(--bg-deep)); padding: 1.25rem 1.35rem; } + .dt-guide .guide-takeaways ul { display: grid; gap: 0.5rem; margin: 0.8rem 0 0; padding-left: 1.1rem; list-style: disc; font-size: 15px; line-height: 1.6; color: var(--foreground); } + .dt-guide .guide-takeaways li::marker { color: var(--primary); } .dt-guide .guide-kicker { margin: 0; font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--primary); } .dt-guide .guide-list { margin: 0 0 1.5rem; padding-left: 1.2rem; list-style: disc; } .dt-guide .guide-list li::marker { color: var(--chart-1); } diff --git a/apps/landing/src/pages/guides/incident-response.astro b/apps/landing/src/pages/guides/incident-response.astro index ccbded0261..f2f61a4dc5 100644 --- a/apps/landing/src/pages/guides/incident-response.astro +++ b/apps/landing/src/pages/guides/incident-response.astro @@ -221,19 +221,28 @@ const articleJsonLd = {
+
+

+ When production breaks at a startup, the one or two engineers on call have to find the problem, fix it and keep customers informed, usually at the same time. Incident response is what a team does from the moment something breaks until users are fine again and the cause is fixed. Every minute of downtime costs orders or signups: in this guide's worked example, a bad deploy fails 23% of checkouts for 18 minutes. When customers notice before your alerts do, you lose some of their trust as well. This guide sets up a process sized for that team: an afternoon of preparation, five response steps and a one-page postmortem. +

+
+

Key takeaways

+
    +
  • Prepare in an afternoon: alerts on symptoms users feel, who gets alerted when, and runbooks for your top three failure modes.
  • +
  • Stop the user impact before you know the cause; a deploy in the last hour is the first suspect, so roll it back.
  • +
  • Declare early in one channel, such as #incidents, and post updates at a fixed interval while customers are affected.
  • +
  • Write a blameless one-page postmortem for incidents customers noticed, with an owner and a due date on every action item.
  • +
  • Once a quarter, count incidents per month, median time to detect and mitigate, and repeat causes.
  • +
+
+
+

01 · The process

How incident response works

-
-

Incident response is what a team does from the moment something breaks in production until users are fine again and the cause is fixed. It runs as a loop: what the team learns from one incident changes the alerts, runbooks and code the next incident meets.

-
- -

- An incident is an unplanned event that hurts users or puts data at risk: an outage, a slow checkout, a leaked credential. -

- This guide is written for startups and small companies. Often one or two engineers are on call, and the engineer who gets paged is the one who fixes the problem, so every step is sized for that. For the formal versions, written for larger security teams, see NIST SP 800-61 and the SANS Incident Handler's Handbook. + An incident is an unplanned event that hurts users or puts data at risk: an outage, a slow checkout, a leaked credential. For the formal process, written for larger security teams, see NIST SP 800-61 and the SANS Incident Handler's Handbook.

The process has four phases. You Prepare on a quiet day. When an alert fires, you Detect and triage, then Mitigate and resolve until users are no longer affected and the system is clean. Afterwards you Learn in a postmortem whose action items go back into preparation: a load test that would have caught the bug, an alert that fires two minutes sooner, a rollback that takes one command. @@ -569,15 +578,16 @@ const articleJsonLd = { .ir-guide h2 { margin: 0 0 1.5rem; font-family: var(--font-display); font-size: clamp(1.75rem, 4vw, 2.5rem); font-weight: 500; line-height: 1.08; letter-spacing: -0.03em; color: var(--foreground); text-wrap: balance; } .ir-guide h3 { margin: 3rem 0 0.8rem; font-family: var(--font-display); font-size: 1.2rem; font-weight: 550; line-height: 1.3; letter-spacing: -0.015em; color: var(--foreground); } .ir-guide h4 { margin: 0; font-family: var(--font-display); font-size: 0.95rem; font-weight: 550; color: var(--foreground); } - .ir-guide > section > p:not(.guide-eyebrow, .guide-kicker, .guide-caption), .ir-guide .guide-answer p { margin: 0 0 1.15rem; font-size: 17px; line-height: 1.7; font-weight: 430; color: color-mix(in oklab, var(--foreground) 85%, var(--background)); } + .ir-guide > section > p:not(.guide-eyebrow, .guide-kicker, .guide-caption) { margin: 0 0 1.15rem; font-size: 17px; line-height: 1.7; font-weight: 430; color: color-mix(in oklab, var(--foreground) 85%, var(--background)); } .ir-guide strong { font-weight: 600; color: var(--foreground); } .ir-guide code:not(pre code) { border: 1px solid var(--border); background: var(--bg-elevated); padding: 0.1rem 0.35rem; font-family: var(--font-mono); font-size: 12px; color: var(--foreground); } .ir-guide pre { margin: 1.25rem 0 1.5rem; overflow-x: auto; border: 1px solid var(--border); border-radius: 0.5rem; background: var(--bg-deep); padding: 0.9rem 1.1rem; font-family: var(--font-mono); font-size: 12px; line-height: 1.75; color: var(--foreground); } .ir-guide a:not(.guide-button) { color: var(--primary); text-decoration: underline; text-decoration-color: color-mix(in oklab, var(--primary) 42%, transparent); text-underline-offset: 3px; transition: color 150ms ease; } .ir-guide a:not(.guide-button):hover { color: var(--foreground); } .ir-guide .guide-caption { margin: 0.7rem 0 0; font-family: var(--font-mono); font-size: 10px; line-height: 1.6; color: var(--muted-foreground); } - .ir-guide .guide-answer { margin: 2rem 0; border-left: 2px solid var(--primary); border-radius: 0 0.5rem 0.5rem 0; background: color-mix(in oklab, var(--primary) 8%, var(--bg-deep)); padding: 1.25rem 1.35rem; } - .ir-guide .guide-answer p { margin: 0; font-size: 16px; line-height: 1.7; color: var(--foreground); } + .ir-guide .guide-takeaways { margin: 2rem 0 0; border-left: 2px solid var(--primary); border-radius: 0 0.5rem 0.5rem 0; background: color-mix(in oklab, var(--primary) 8%, var(--bg-deep)); padding: 1.25rem 1.35rem; } + .ir-guide .guide-takeaways ul { display: grid; gap: 0.5rem; margin: 0.8rem 0 0; padding-left: 1.1rem; list-style: disc; font-size: 15px; line-height: 1.6; color: var(--foreground); } + .ir-guide .guide-takeaways li::marker { color: var(--primary); } .ir-guide .guide-kicker { margin: 0; font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--primary); } /* One color per NIST phase: set --phase on the element. */ diff --git a/apps/landing/src/pages/guides/log-parsing.astro b/apps/landing/src/pages/guides/log-parsing.astro index d1eebbb8ba..e191ef5fcf 100644 --- a/apps/landing/src/pages/guides/log-parsing.astro +++ b/apps/landing/src/pages/guides/log-parsing.astro @@ -29,13 +29,14 @@ const authorUrl = `https://github.com/${author.github}`; const toc = [ { depth: 2, slug: "definition", text: "Log parsing, defined" }, { depth: 2, slug: "formats", text: "Formats and techniques" }, + { depth: 3, slug: "tools", text: "Log parsing tools" }, { depth: 2, slug: "collector", text: "The OpenTelemetry Collector" }, { depth: 3, slug: "file-log", text: "The file log receiver" }, { depth: 3, slug: "config", text: "Pick your log format" }, { depth: 3, slug: "run", text: "Run it" }, { depth: 3, slug: "see", text: "See the parsed fields" }, { depth: 2, slug: "own-format", text: "Parse your own format" }, - { depth: 2, slug: "mistakes", text: "Common mistakes" }, + { depth: 2, slug: "mistakes", text: "Best practices and mistakes" }, { depth: 2, slug: "by-hand", text: "Parse a file by hand" }, ]; const sectionNav = toc.filter((h) => h.depth === 2); @@ -312,6 +313,16 @@ const checkOutput = `{'client_address': '203.0.113.7', 'time_local': '19/Oct/202 no match on line 6: 192.0.2.44 - - [19/Oct/2026:14:02:17 +0000] "\\x16\\x03\\x01\\x0 1 lines did not match`; +// Facts from each vendor's own page, last verified 2026-10-31. +const tools = [ + ["OpenTelemetry Collector", "https://opentelemetry.io/docs/collector/", "Vendor-agnostic pipeline that receives, processes and exports logs, metrics and traces", "Open source, Apache 2.0", "Free", "Parsing once and sending to any OTLP backend"], + ["Fluent Bit", "https://fluentbit.io/", "Lightweight processor and forwarder for logs, metrics and traces; a CNCF graduated project", "Open source, Apache 2.0", "Free", "An agent on every node or container"], + ["Logstash", "https://www.elastic.co/logstash", "Elastic's server-side pipeline; grok turns unstructured text into fields", "Apache 2.0 for the -oss build, Elastic License for the default build", "Free to self-host", "Elastic Stack users and grok patterns"], + ["Vector", "https://vector.dev/", "Observability pipeline maintained by Datadog; parses with Vector Remap Language", "Open source, MPL 2.0", "Free", "Programmable transforms in one binary"], + ["Graylog", "https://graylog.org/products/source-available/", "Log management with pipeline processing, search and alerts", "Graylog Open: SSPL; Enterprise and Security editions are paid", "Open is free; Enterprise uses value-based licensing", "Self-hosted log search with parsing built in"], + ["Splunk", "https://www.splunk.com/en_us/products/pricing.html", "Commercial data platform; the rex command extracts fields with a regex at search time", "Proprietary", "Ingest, workload, entity or activity pricing; free trials", "Teams already on Splunk"], +]; + const mistakes = [ ["A loose regex", "Anchor the pattern with ^ and $ so a partial match can't fill half the fields, and use negated classes such as [^\"]* instead of .*, which backtracks across the rest of the line."], ["Keeping query strings", "Query strings carry session tokens, emails and IDs. The path group in this guide stops at ?, so they never reach an attribute."], @@ -432,14 +443,27 @@ const articleJsonLd = {

+
+

+ Something broke, and the answer is somewhere in a few million log lines. A log is the text record a program writes as it runs, one line per request, error or event. Log parsing is splitting each line into named fields, such as the time, the status code or the URL path, so tools can filter and count by those fields instead of searching the text. Without it, an alert on the error rate or a chart of the busiest endpoints has nothing to count, because the status code and the path are buried inside a string. This guide covers the common log formats and the tools that parse them, with an OpenTelemetry Collector config you can run for each format. +

+ +
+

Key takeaways

+
    +
  • The format decides the parser: JSON, logfmt and syslog have their own, other text needs a regex with named groups.
  • +
  • Parse once in a pipeline such as the OpenTelemetry Collector, so every backend gets the same fields.
  • +
  • Convert status codes and sizes to integers: as text, "502" >= "60" is false.
  • +
  • Let lines that don't match through with their raw body; they are often the ones worth reading.
  • +
  • For code you own, log JSON from a structured logger instead of parsing text later.
  • +
+
+
+

01 · Definition

Log parsing, defined

-
-

Log parsing is splitting each line of a log into named fields, such as the time, the status code or the URL path. Tools can then filter and count by those fields instead of searching the text.

-
-

Here is one request from an nginx access log, before and after parsing. Each color is one field, and the same colors mark that field in the regex and config further down.

@@ -491,6 +515,23 @@ const articleJsonLd = {

Any text format without a dedicated parser falls back to a regular expression, where each named group, written (?P<name>...), becomes a field. Grok, popularized by Logstash, is regex with a library of ready-made named patterns: %{IP:client} matches an IP address, and %{HTTPD_COMBINEDLOG} matches a whole nginx or Apache line. The next section has a Collector config for each format in the table.

+ +

Log parsing tools

+
+ + + + + + {tools.map(([name, url, what, license, pricing, bestFor]) => ( + + ))} + +
ToolWhat it isLicensePricingBest for
{name}{what}{license}{pricing}{bestFor}
+
+

+ Maple stores logs that arrive over OTLP, so this guide parses them in the Collector before they are sent. +

@@ -629,8 +670,8 @@ const articleJsonLd = {
-

05 · Mistakes

-

Common log parsing mistakes

+

05 · Best practices

+

Log parsing best practices and common mistakes

A parser that looks right on the sample line can still lose data in these ways:

{mistakes.map(([title, body], index) => ( @@ -733,7 +774,7 @@ const articleJsonLd = { .lp-guide h2 { margin: 0 0 1.5rem; font-family: var(--font-display); font-size: clamp(1.75rem, 4vw, 2.5rem); font-weight: 500; line-height: 1.08; letter-spacing: -0.03em; color: var(--foreground); text-wrap: balance; } .lp-guide h3 { margin: 3rem 0 0.8rem; font-family: var(--font-display); font-size: 1.2rem; font-weight: 550; line-height: 1.3; letter-spacing: -0.015em; color: var(--foreground); } .lp-guide h4 { margin: 0; font-family: var(--font-display); font-size: 0.95rem; font-weight: 550; color: var(--foreground); } - .lp-guide > section > p:not(.guide-eyebrow, .guide-kicker, .guide-caption), .lp-guide .guide-answer p { margin: 0 0 1.15rem; font-size: 17px; line-height: 1.7; font-weight: 430; color: color-mix(in oklab, var(--foreground) 85%, var(--background)); } + .lp-guide > section > p:not(.guide-eyebrow, .guide-kicker, .guide-caption) { margin: 0 0 1.15rem; font-size: 17px; line-height: 1.7; font-weight: 430; color: color-mix(in oklab, var(--foreground) 85%, var(--background)); } .lp-guide strong { font-weight: 600; color: var(--foreground); } .lp-guide code:not(pre code) { border: 1px solid var(--border); background: var(--bg-elevated); padding: 0.1rem 0.35rem; font-family: var(--font-mono); font-size: 12px; color: var(--foreground); overflow-wrap: anywhere; } .lp-guide pre { position: relative; margin: 1.25rem 0 1.5rem; overflow-x: auto; border: 1px solid var(--border); border-radius: 0.5rem; background: var(--bg-deep); padding: 0.9rem 1.1rem; font-family: var(--font-mono); font-size: 12px; line-height: 1.75; color: var(--foreground); tab-size: 4; } @@ -745,9 +786,10 @@ const articleJsonLd = { .lp-guide .guide-list li::marker { color: var(--primary); } .lp-guide a:not(.guide-button) { color: var(--primary); text-decoration: underline; text-decoration-color: color-mix(in oklab, var(--primary) 42%, transparent); text-underline-offset: 3px; transition: color 150ms ease; } .lp-guide a:not(.guide-button):hover { color: var(--foreground); } - .lp-guide .guide-answer { margin: 2rem 0; border-left: 2px solid var(--primary); border-radius: 0 0.5rem 0.5rem 0; background: color-mix(in oklab, var(--primary) 8%, var(--bg-deep)); padding: 1.25rem 1.35rem; } - .lp-guide .guide-answer p { margin: 0; font-size: 16px; line-height: 1.7; color: var(--foreground); } .lp-guide .guide-kicker { margin: 0; font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--primary); } + .lp-guide .guide-takeaways { margin: 2rem 0 0; border-left: 2px solid var(--primary); border-radius: 0 0.5rem 0.5rem 0; background: color-mix(in oklab, var(--primary) 8%, var(--bg-deep)); padding: 1.25rem 1.35rem; } + .lp-guide .guide-takeaways ul { display: grid; gap: 0.5rem; margin: 0.8rem 0 0; padding-left: 1.1rem; list-style: disc; font-size: 15px; line-height: 1.6; color: var(--foreground); } + .lp-guide .guide-takeaways li::marker { color: var(--primary); } /* Syntax colors stay neutral or in the page accent, so the field colors are the only hues in code. */ .lp-guide .tok-comment { color: var(--muted-foreground); } diff --git a/apps/landing/src/pages/guides/loguru.astro b/apps/landing/src/pages/guides/loguru.astro index d90e1c4d4a..b0065dd710 100644 --- a/apps/landing/src/pages/guides/loguru.astro +++ b/apps/landing/src/pages/guides/loguru.astro @@ -419,17 +419,26 @@ const articleJsonLd = {
-
-

01 · Basics

-

Get started with Loguru

+
+

+ Your Python app needs logs you can read when something breaks, and the standard logging module makes you wire up handlers and formatters before you get a rotating log file or JSON lines. Loguru is a popular logging library for Python that takes almost no setup: you import one ready-made logger and call it. In production, a log file without rotation grows until the disk is full, and lines from requests handled at the same time interleave with nothing to tell them apart. This guide takes you from the first line to JSON log files and an observability tool that shows which request wrote each line. +

-
-

Loguru is a popular logging library for Python that takes almost no setup. You import one ready-made logger and call it.

+
+

Key takeaways

+
    +
  • from loguru import logger is the whole setup; logger.add() adds sinks such as files.
  • +
  • rotation and retention on a file sink keep log files from filling the disk.
  • +
  • serialize=True writes JSON lines that log search tools can filter field by field.
  • +
  • Add production sinks with diagnose=False so tracebacks don't print passwords and tokens.
  • +
  • In a package other people install, log with the standard logging module; use Loguru in your own apps.
  • +
+
-

- This guide starts with your first log line and then adds what most apps need: a log level, log files, JSON output and extra context on each line. The last section sends your Loguru logs to an observability tool, where you can search them and see which request wrote each line. -

+
+

01 · Basics

+

Get started with Loguru

Install Loguru with pip, then import logger and start logging. Loguru prints colored lines to your terminal out of the box:

{installCommand}
@@ -750,7 +759,7 @@ const articleJsonLd = { .loguru-guide h2 { margin: 0 0 1.5rem; font-family: var(--font-display); font-size: clamp(1.75rem, 4vw, 2.5rem); font-weight: 500; line-height: 1.08; letter-spacing: -0.03em; color: var(--foreground); text-wrap: balance; } .loguru-guide h3 { display: flex; align-items: center; gap: 0.6rem; margin: 3rem 0 0.8rem; font-family: var(--font-display); font-size: 1.2rem; font-weight: 550; line-height: 1.3; letter-spacing: -0.015em; color: var(--foreground); } .loguru-guide h4 { margin: 0; font-family: var(--font-display); font-size: 0.95rem; font-weight: 550; color: var(--foreground); } - .loguru-guide > section > p:not(.guide-eyebrow, .guide-kicker), .loguru-guide .guide-answer p { margin: 0 0 1.15rem; font-size: 17px; line-height: 1.7; font-weight: 430; color: color-mix(in oklab, var(--foreground) 85%, var(--background)); } + .loguru-guide > section > p:not(.guide-eyebrow, .guide-kicker) { margin: 0 0 1.15rem; font-size: 17px; line-height: 1.7; font-weight: 430; color: color-mix(in oklab, var(--foreground) 85%, var(--background)); } .loguru-guide strong { font-weight: 600; color: var(--foreground); } .loguru-guide code:not(pre code) { border: 1px solid var(--border); background: var(--bg-elevated); padding: 0.1rem 0.35rem; font-family: var(--font-mono); font-size: 12px; color: var(--foreground); overflow-wrap: anywhere; } .loguru-guide pre { position: relative; margin: 1.25rem 0 1.5rem; overflow-x: auto; border: 1px solid var(--border); border-radius: 0.5rem; background: var(--bg-deep); padding: 0.9rem 1.1rem; font-family: var(--font-mono); font-size: 12px; line-height: 1.75; color: var(--foreground); } @@ -761,9 +770,10 @@ const articleJsonLd = { .loguru-guide pre + .pre-output { margin-top: -1rem; border-top-left-radius: 0; border-top-right-radius: 0; background: color-mix(in oklab, var(--background) 70%, var(--bg-deep)); } .loguru-guide a:not(.guide-button) { color: var(--primary); text-decoration: underline; text-decoration-color: color-mix(in oklab, var(--primary) 42%, transparent); text-underline-offset: 3px; transition: color 150ms ease; } .loguru-guide a:not(.guide-button):hover { color: var(--foreground); } - .loguru-guide .guide-answer { margin: 2rem 0; border-left: 2px solid var(--primary); border-radius: 0 0.5rem 0.5rem 0; background: color-mix(in oklab, var(--primary) 8%, var(--bg-deep)); padding: 1.25rem 1.35rem; } - .loguru-guide .guide-answer p { margin: 0; font-size: 16px; line-height: 1.7; color: var(--foreground); } .loguru-guide .guide-kicker { margin: 0; font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--primary); } + .loguru-guide .guide-takeaways { margin: 2rem 0 0; border-left: 2px solid var(--primary); border-radius: 0 0.5rem 0.5rem 0; background: color-mix(in oklab, var(--primary) 8%, var(--bg-deep)); padding: 1.25rem 1.35rem; } + .loguru-guide .guide-takeaways ul { display: grid; gap: 0.5rem; margin: 0.8rem 0 0; padding-left: 1.1rem; list-style: disc; font-size: 15px; line-height: 1.6; color: var(--foreground); } + .loguru-guide .guide-takeaways li::marker { color: var(--primary); } /* One color per system: set --sys on the element. */ .loguru-guide .sys-badge { display: inline-flex; align-items: center; border: 1px solid color-mix(in oklab, var(--sys) 45%, transparent); border-radius: 999px; background: color-mix(in oklab, var(--sys) 14%, transparent); padding: 0.15rem 0.6rem; font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.04em; text-transform: none; color: color-mix(in oklab, var(--sys) 70%, var(--foreground)); white-space: nowrap; } diff --git a/apps/landing/src/pages/guides/new-relic-pricing.astro b/apps/landing/src/pages/guides/new-relic-pricing.astro index 1961053f9b..c4072e1f61 100644 --- a/apps/landing/src/pages/guides/new-relic-pricing.astro +++ b/apps/landing/src/pages/guides/new-relic-pricing.astro @@ -152,6 +152,16 @@ const faqs = [ answer: "Users plus data. On Standard, the first full platform user is $10 a month and each additional one $99 a month, up to five. On Pro each full platform user is $349 a month with a 1-year commitment, or $418.80 a month without one. Core users are $49 a month on any paid plan, and every GB past the first 100 is $0.40. A 12-person team sending 800 GB pays about $979 a month with 4 full platform and 8 core users on Standard, or $4,468 with all 12 on Pro.", }, + { + question: "Why is New Relic expensive?", + answer: + "Mostly because of full platform users. Anyone who needs the APM, infrastructure or browser views, including whoever is on call, needs one: $99 a month on Standard and $349 on Pro with a 1-year commitment. Twelve full platform users on Pro cost $4,188 a month before any data.", + }, + { + question: "Are there hidden costs in New Relic pricing?", + answer: + "Not hidden, but some sit outside the headline rates. Data Plus raises data from $0.40 to $0.60 per GB, storing data in the EU region adds $0.05 per GB, synthetic checks past your edition's allowance cost $0.005 each, and extended retention and Advanced Compute are paid add-ons.", + }, { question: "What happens past 100 GB on the New Relic free tier?", answer: @@ -248,14 +258,26 @@ const articleJsonLd = {
+
+

+ New Relic's pricing page lists four editions and three kinds of user, but not what your team will pay. New Relic is a monitoring platform: it collects data from your applications and servers, and lets you search it, chart it and get alerted when something breaks. You pay per user and per GB of data: the first 100 GB each month is free, every GB after it costs $0.40, and hosts cost nothing. That makes headcount the number to watch: a sixth engineer who needs the APM views moves you from Standard to Pro, where each full platform user costs $349 a month with a 1-year commitment instead of $99. By the end you can price your own team and pick the cheapest mix of user types. +

+
+

Key takeaways

+
    +
  • The free tier includes 100 GB of data a month, one full platform user and unlimited basic users, with no time limit.
  • +
  • Data past 100 GB costs $0.40 per GB ($0.60 with Data Plus); hosts, agents and containers are free.
  • +
  • Full platform users cost $10 for the first and $99 for each after on Standard (5 at most), $349 on Pro with a 1-year commitment.
  • +
  • Core users cost $49 a month and get logs and errors, but not the APM or infrastructure screens.
  • +
  • On the free tier, passing 100 GB stops ingest and platform access until the next month.
  • +
+
+
+

01 · Pricing model

The New Relic pricing model

-
-

New Relic charges for two things: the people who use it and the data you send it. The first 100 GB of data each month is free, and every GB after that costs $0.40.

-
-

People are billed by user type, and only two of the three types cost money. The plan, called an edition (Free, Standard, Pro or Enterprise), sets the price of a full platform user, how many you can add and the support level.

@@ -638,15 +660,16 @@ const articleJsonLd = { .nr-guide h2 { margin: 0 0 1.5rem; font-family: var(--font-display); font-size: clamp(1.75rem, 4vw, 2.5rem); font-weight: 500; line-height: 1.08; letter-spacing: -0.03em; color: var(--foreground); text-wrap: balance; } .nr-guide h3 { margin: 3rem 0 0.8rem; font-family: var(--font-display); font-size: 1.2rem; font-weight: 550; line-height: 1.3; letter-spacing: -0.015em; color: var(--foreground); } .nr-guide h4 { margin: 0; font-family: var(--font-display); font-size: 0.95rem; font-weight: 550; color: var(--foreground); } - .nr-guide > section > p:not(.guide-eyebrow, .guide-kicker, .guide-caption), .nr-guide .guide-answer p { margin: 0 0 1.15rem; font-size: 17px; line-height: 1.7; font-weight: 430; color: color-mix(in oklab, var(--foreground) 85%, var(--background)); } + .nr-guide > section > p:not(.guide-eyebrow, .guide-kicker, .guide-caption) { margin: 0 0 1.15rem; font-size: 17px; line-height: 1.7; font-weight: 430; color: color-mix(in oklab, var(--foreground) 85%, var(--background)); } .nr-guide strong { font-weight: 600; color: var(--foreground); } .nr-guide code:not(pre code) { border: 1px solid var(--border); background: var(--bg-elevated); padding: 0.1rem 0.35rem; font-family: var(--font-mono); font-size: 12px; color: var(--foreground); } .nr-guide pre { margin: 1rem 0 1.25rem; overflow-x: auto; border: 1px solid var(--border); border-radius: 0.5rem; background: var(--bg-deep); padding: 0.9rem 1.1rem; font-family: var(--font-mono); font-size: 12px; line-height: 1.75; color: var(--foreground); } .nr-guide a:not(.guide-button) { color: var(--primary); text-decoration: underline; text-decoration-color: color-mix(in oklab, var(--primary) 42%, transparent); text-underline-offset: 3px; transition: color 150ms ease; } .nr-guide a:not(.guide-button):hover { color: var(--foreground); } .nr-guide .guide-caption { margin: 0.7rem 0 1.5rem; font-family: var(--font-mono); font-size: 10px; line-height: 1.6; color: var(--muted-foreground); } - .nr-guide .guide-answer { margin: 2rem 0; border-left: 2px solid var(--primary); border-radius: 0 0.5rem 0.5rem 0; background: color-mix(in oklab, var(--primary) 8%, var(--bg-deep)); padding: 1.25rem 1.35rem; } - .nr-guide .guide-answer p { margin: 0; font-size: 16px; line-height: 1.7; color: var(--foreground); } + .nr-guide .guide-takeaways { margin: 2rem 0 0; border-left: 2px solid var(--primary); border-radius: 0 0.5rem 0.5rem 0; background: color-mix(in oklab, var(--primary) 8%, var(--bg-deep)); padding: 1.25rem 1.35rem; } + .nr-guide .guide-takeaways ul { display: grid; gap: 0.5rem; margin: 0.8rem 0 0; padding-left: 1.1rem; list-style: disc; font-size: 15px; line-height: 1.6; color: var(--foreground); } + .nr-guide .guide-takeaways li::marker { color: var(--primary); } .nr-guide .guide-kicker { margin: 0; font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--primary); } /* Code: keywords in the accent, names in teal; neither color is a billing meter. */ diff --git a/apps/landing/src/pages/guides/pino-logger.astro b/apps/landing/src/pages/guides/pino-logger.astro index 530655c5b0..77d8468232 100644 --- a/apps/landing/src/pages/guides/pino-logger.astro +++ b/apps/landing/src/pages/guides/pino-logger.astro @@ -398,14 +398,27 @@ const articleJsonLd = {
+
+

+ Most Node.js apps start logging with console.log. It has no levels you can turn down in production, and it writes plain text that a log tool can only match as strings. Pino is a logger for Node.js that writes each log entry as one line of JSON, built to add as little work as possible to the code that serves your requests. Levels and JSON fields let you switch debug output off in production and find one failed checkout by its order ID instead of grepping text. By the end, every line your service writes is JSON with secrets redacted, and carries the trace ID of the request that wrote it. +

+ +
+

Key takeaways

+
    +
  • Pass data as an object first: logger.info({ orderId }, "order created") gives you a field to search.
  • +
  • A child logger adds a request ID or tenant to every line it writes.
  • +
  • List secret paths in redact; a token under an unlisted key still goes out in clear text.
  • +
  • Use pino-pretty in development only and keep production output as JSON.
  • +
  • With the OpenTelemetry Pino instrumentation, each line carries the trace ID of the request that wrote it.
  • +
+
+
+

01 · Definition

Pino, the JSON logger for Node.js

-
-

Pino is a logger for Node.js that writes each log entry as one line of JSON. It is built to add as little work as possible to the code that serves your requests.

-
-

JSON lines suit services that run in containers or on platforms that collect stdout: whatever reads the output can filter on fields instead of matching text. Pino is MIT-licensed, Fastify uses it as its built-in logger, and pino-http adds request logging to Express and plain http servers.

@@ -708,7 +721,10 @@ const articleJsonLd = {

- Choose Pino when logs are JSON headed for a collector and per-call cost matters; Pino publishes its own benchmarks against other loggers. Choose Winston when the process itself must write several formats to several destinations, or an existing codebase depends on its format pipeline. Moving between them is mostly mechanical: both take a metadata object and a message, and Pino puts the object first. + In Pino's own benchmark, a run of logger.info('hello world') calls averaged 114.8 ms with Pino and 270.2 ms with Winston. +

+

+ Choose Pino when logs are JSON headed for a collector and per-call cost matters. Choose Winston when the process itself must write several formats to several destinations, or an existing codebase depends on its format pipeline. Moving between them is mostly mechanical: both take a metadata object and a message, and Pino puts the object first.

@@ -745,16 +761,17 @@ const articleJsonLd = { .pino-guide h2 { margin: 0 0 1.5rem; font-family: var(--font-display); font-size: clamp(1.75rem, 4vw, 2.5rem); font-weight: 500; line-height: 1.08; letter-spacing: -0.03em; color: var(--foreground); text-wrap: balance; } .pino-guide h3 { display: flex; align-items: center; gap: 0.6rem; margin: 3rem 0 0.8rem; font-family: var(--font-display); font-size: 1.2rem; font-weight: 550; line-height: 1.3; letter-spacing: -0.015em; color: var(--foreground); } .pino-guide h4 { margin: 0; font-family: var(--font-display); font-size: 0.95rem; font-weight: 550; color: var(--foreground); } - .pino-guide > section > p:not(.guide-eyebrow, .guide-kicker, .guide-caption), .pino-guide .guide-answer p { margin: 0 0 1.15rem; font-size: 17px; line-height: 1.7; font-weight: 430; color: color-mix(in oklab, var(--foreground) 85%, var(--background)); } + .pino-guide > section > p:not(.guide-eyebrow, .guide-kicker, .guide-caption) { margin: 0 0 1.15rem; font-size: 17px; line-height: 1.7; font-weight: 430; color: color-mix(in oklab, var(--foreground) 85%, var(--background)); } .pino-guide strong { font-weight: 600; color: var(--foreground); } .pino-guide code:not(pre code) { border: 1px solid var(--border); background: var(--bg-elevated); padding: 0.1rem 0.35rem; font-family: var(--font-mono); font-size: 12px; color: var(--foreground); } .pino-guide pre { margin: 1.25rem 0 1.5rem; overflow-x: auto; border: 1px solid var(--border); border-radius: 0.5rem; background: var(--bg-deep); padding: 0.9rem 1.1rem; font-family: var(--font-mono); font-size: 12px; line-height: 1.75; color: var(--foreground); } .pino-guide a:not(.guide-button) { color: var(--primary); text-decoration: underline; text-decoration-color: color-mix(in oklab, var(--primary) 42%, transparent); text-underline-offset: 3px; transition: color 150ms ease; } .pino-guide a:not(.guide-button):hover { color: var(--foreground); } .pino-guide .guide-caption { margin: 0.7rem 0 0; font-family: var(--font-mono); font-size: 10px; line-height: 1.6; color: var(--muted-foreground); } - .pino-guide .guide-answer { margin: 2rem 0; border-left: 2px solid var(--primary); border-radius: 0 0.5rem 0.5rem 0; background: color-mix(in oklab, var(--primary) 8%, var(--bg-deep)); padding: 1.25rem 1.35rem; } - .pino-guide .guide-answer p { margin: 0; font-size: 16px; line-height: 1.7; color: var(--foreground); } .pino-guide .guide-kicker { margin: 0; font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--primary); } + .pino-guide .guide-takeaways { margin: 2rem 0 0; border-left: 2px solid var(--primary); border-radius: 0 0.5rem 0.5rem 0; background: color-mix(in oklab, var(--primary) 8%, var(--bg-deep)); padding: 1.25rem 1.35rem; } + .pino-guide .guide-takeaways ul { display: grid; gap: 0.5rem; margin: 0.8rem 0 0; padding-left: 1.1rem; list-style: disc; font-size: 15px; line-height: 1.6; color: var(--foreground); } + .pino-guide .guide-takeaways li::marker { color: var(--primary); } .pino-guide .guide-list { display: grid; gap: 0.6rem; margin: 1.25rem 0 1.5rem; padding-left: 1.1rem; list-style: disc; font-size: 15px; line-height: 1.65; color: color-mix(in oklab, var(--foreground) 80%, var(--background)); } .pino-guide .guide-list li::marker { color: var(--primary); } diff --git a/apps/landing/src/pages/guides/prometheus-metrics.astro b/apps/landing/src/pages/guides/prometheus-metrics.astro index 571da3a3bb..3ca21ec135 100644 --- a/apps/landing/src/pages/guides/prometheus-metrics.astro +++ b/apps/landing/src/pages/guides/prometheus-metrics.astro @@ -335,14 +335,27 @@ const articleJsonLd = {
+
+

+ You shipped a service and want to know how it is doing right now: how many requests it handles, how many fail, how slow the slow ones are. Prometheus is a free, open-source monitoring system that collects those numbers. A Prometheus metric is one of them: a named number your app keeps up to date, such as requests served, which Prometheus reads every few seconds and stores so you can chart it and alert on it. Without metrics, you hear about a slow checkout or a full disk from a customer, with no history to show when it started. By the end of this guide you'll have an app publishing metrics, plus Prometheus and Grafana running locally to chart them. +

+ +
+

Key takeaways

+
    +
  • Counters only go up: chart them with rate() or increase(), never raw.
  • +
  • Gauges go up and down: read the value directly.
  • +
  • Use a histogram for latency. Its buckets add up across instances; summary percentiles don't.
  • +
  • Start with request rate, error ratio and p95 latency, and alert on up == 0.
  • +
  • Keep user IDs and full URLs out of labels: every label value is a new time series.
  • +
+
+
+

01 · Definition

What a Prometheus metric is

-
-

A Prometheus metric is a named number that your application keeps up to date, such as how many requests it has served. Prometheus reads it every few seconds and stores each reading, so you can chart how the number changes over time.

-
-

Applications publish their metrics as plain text on an HTTP endpoint, usually /metrics. Every line is one number:

@@ -514,6 +527,14 @@ const articleJsonLd = { + +

Which type should I use?

+
    +
  • It counts things that happen, such as requests or errors: Counter
  • +
  • It can go down for a reason other than a restart: Gauge
  • +
  • You need percentiles, such as p95 latency: Histogram
  • +
  • One process, with percentiles you know in advance: Summary works, but a histogram still does more
  • +
@@ -686,16 +707,18 @@ const articleJsonLd = { .prom-guide h2 { margin: 0 0 1.5rem; font-family: var(--font-display); font-size: clamp(1.75rem, 4vw, 2.5rem); font-weight: 500; line-height: 1.08; letter-spacing: -0.03em; color: var(--foreground); text-wrap: balance; } .prom-guide h3 { display: flex; align-items: center; gap: 0.6rem; margin: 3rem 0 0.8rem; font-family: var(--font-display); font-size: 1.2rem; font-weight: 550; line-height: 1.3; letter-spacing: -0.015em; color: var(--foreground); } .prom-guide h4 { margin: 0; font-family: var(--font-display); font-size: 0.95rem; font-weight: 550; color: var(--foreground); } - .prom-guide > section > p:not(.guide-eyebrow, .guide-kicker, .guide-caption), .prom-guide .guide-answer p { margin: 0 0 1.15rem; font-size: 17px; line-height: 1.7; font-weight: 430; color: color-mix(in oklab, var(--foreground) 85%, var(--background)); } + .prom-guide > section > p:not(.guide-eyebrow, .guide-kicker, .guide-caption) { margin: 0 0 1.15rem; font-size: 17px; line-height: 1.7; font-weight: 430; color: color-mix(in oklab, var(--foreground) 85%, var(--background)); } .prom-guide strong { font-weight: 600; color: var(--foreground); } .prom-guide code:not(pre code) { border: 1px solid var(--border); background: var(--bg-elevated); padding: 0.1rem 0.35rem; font-family: var(--font-mono); font-size: 12px; color: var(--foreground); } .prom-guide pre { margin: 1.25rem 0 1.5rem; overflow-x: auto; border: 1px solid var(--border); border-radius: 0.5rem; background: var(--bg-deep); padding: 0.9rem 1.1rem; font-family: var(--font-mono); font-size: 12px; line-height: 1.75; color: var(--foreground); } .prom-guide a:not(.guide-button) { color: var(--primary); text-decoration: underline; text-decoration-color: color-mix(in oklab, var(--primary) 42%, transparent); text-underline-offset: 3px; transition: color 150ms ease; } .prom-guide a:not(.guide-button):hover { color: var(--foreground); } .prom-guide .guide-caption { margin: 0.7rem 0 0; font-family: var(--font-mono); font-size: 10px; line-height: 1.6; color: var(--muted-foreground); } - .prom-guide .guide-answer { margin: 2rem 0; border-left: 2px solid var(--primary); border-radius: 0 0.5rem 0.5rem 0; background: color-mix(in oklab, var(--primary) 8%, var(--bg-deep)); padding: 1.25rem 1.35rem; } - .prom-guide .guide-answer p { margin: 0; font-size: 16px; line-height: 1.7; color: var(--foreground); } .prom-guide .guide-kicker { margin: 0; font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--primary); } + .prom-guide .guide-takeaways { margin: 2rem 0 0; border-left: 2px solid var(--primary); border-radius: 0 0.5rem 0.5rem 0; background: color-mix(in oklab, var(--primary) 8%, var(--bg-deep)); padding: 1.25rem 1.35rem; } + .prom-guide .guide-takeaways ul { display: grid; gap: 0.5rem; margin: 0.8rem 0 0; padding-left: 1.1rem; list-style: disc; font-size: 15px; line-height: 1.6; color: var(--foreground); } + .prom-guide .guide-takeaways li::marker { color: var(--primary); } + .prom-guide .guide-list { display: grid; gap: 0.6rem; margin: 0 0 1.5rem; padding-left: 1.2rem; list-style: disc; font-size: 16px; line-height: 1.7; color: color-mix(in oklab, var(--foreground) 85%, var(--background)); } /* One color per metric type: set --type on the element. */ .prom-guide .type-badge { display: inline-flex; align-items: center; gap: 0.4rem; border: 1px solid color-mix(in oklab, var(--type) 45%, transparent); border-radius: 999px; background: color-mix(in oklab, var(--type) 14%, transparent); padding: 0.15rem 0.6rem; font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.04em; color: color-mix(in oklab, var(--type) 70%, var(--foreground)); white-space: nowrap; } diff --git a/apps/landing/src/pages/guides/python-logging-levels.astro b/apps/landing/src/pages/guides/python-logging-levels.astro index 36289d204c..0d6eee8a1c 100644 --- a/apps/landing/src/pages/guides/python-logging-levels.astro +++ b/apps/landing/src/pages/guides/python-logging-levels.astro @@ -311,14 +311,27 @@ const articleJsonLd = {
+
+

+ Your program prints hundreds of lines while it runs, and the one warning that explains a failed payment is somewhere in the middle. Python's built-in logging module is the standard way to write those lines. It gives each message a log level, a label that says how serious it is, and drops every message below the level you choose. The level also decides what you pay for: at DEBUG, a busy service writes far more lines than at INFO, and a log service bills you to ingest and store every one of them. By the end of this guide you'll run production at INFO, switch on DEBUG without editing code, and keep noisy libraries quiet. +

+ +
+

Key takeaways

+
    +
  • Python's default level is WARNING, so info() and debug() print nothing until you set one.
  • +
  • Run production at INFO and switch to DEBUG only while you investigate.
  • +
  • Read the level from a --log-level flag or a LOG_LEVEL variable, so changing it needs no code edit.
  • +
  • basicConfig does nothing if logging is already set up: pass force=True or set the root logger's level.
  • +
  • Set library loggers such as urllib3 to WARNING to hide their DEBUG and INFO lines.
  • +
+
+
+

01 · Basics

The Python logging levels

-
-

A log level is a label on each log message that says how serious it is. You choose a level for your program, and Python drops every message below it.

-
-

The method you call sets a message's level: log.debug(), log.info(), log.warning(), log.error() or log.critical(). These are the five levels, from least to most serious:

@@ -389,7 +402,7 @@ const articleJsonLd = {

basicConfig runs once

-

If a framework or library already set up logging, basicConfig silently does nothing. Set the level directly instead:

+

If a framework or library already set up logging, basicConfig silently does nothing. Pass force=True to replace the existing setup, or set the level directly instead:

@@ -536,16 +549,17 @@ const articleJsonLd = { .pylog-guide h2 { margin: 0 0 1.5rem; font-family: var(--font-display); font-size: clamp(1.75rem, 4vw, 2.5rem); font-weight: 500; line-height: 1.08; letter-spacing: -0.03em; color: var(--foreground); text-wrap: balance; } .pylog-guide h3 { margin: 3rem 0 0.8rem; font-family: var(--font-display); font-size: 1.2rem; font-weight: 550; line-height: 1.3; letter-spacing: -0.015em; color: var(--foreground); } .pylog-guide h4 { margin: 0; font-family: var(--font-display); font-size: 0.95rem; font-weight: 550; color: var(--foreground); } - .pylog-guide > section > p:not(.guide-eyebrow, .guide-kicker, .guide-caption), .pylog-guide .guide-answer p { margin: 0 0 1.15rem; font-size: 17px; line-height: 1.7; font-weight: 430; color: color-mix(in oklab, var(--foreground) 85%, var(--background)); } + .pylog-guide > section > p:not(.guide-eyebrow, .guide-kicker, .guide-caption) { margin: 0 0 1.15rem; font-size: 17px; line-height: 1.7; font-weight: 430; color: color-mix(in oklab, var(--foreground) 85%, var(--background)); } .pylog-guide strong { font-weight: 600; color: var(--foreground); } .pylog-guide code:not(pre code) { border: 1px solid var(--border); background: var(--bg-elevated); padding: 0.1rem 0.35rem; font-family: var(--font-mono); font-size: 12px; color: var(--foreground); } .pylog-guide pre { position: relative; margin: 1.25rem 0 1.5rem; overflow-x: auto; border: 1px solid var(--border); border-radius: 0.5rem; background: var(--bg-deep); padding: 0.9rem 1.1rem; font-family: var(--font-mono); font-size: 12px; line-height: 1.75; color: var(--foreground); } .pylog-guide a:not(.guide-button) { color: var(--primary); text-decoration: underline; text-decoration-color: color-mix(in oklab, var(--primary) 42%, transparent); text-underline-offset: 3px; transition: color 150ms ease; } .pylog-guide a:not(.guide-button):hover { color: var(--foreground); } .pylog-guide .guide-caption { margin: 0.7rem 0 0; font-family: var(--font-mono); font-size: 10px; line-height: 1.6; color: var(--muted-foreground); } - .pylog-guide .guide-answer { margin: 2rem 0; border-left: 2px solid var(--primary); border-radius: 0 0.5rem 0.5rem 0; background: color-mix(in oklab, var(--primary) 8%, var(--bg-deep)); padding: 1.25rem 1.35rem; } - .pylog-guide .guide-answer p { margin: 0; font-size: 16px; line-height: 1.7; color: var(--foreground); } .pylog-guide .guide-kicker { margin: 0; font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--primary); } + .pylog-guide .guide-takeaways { margin: 2rem 0 0; border-left: 2px solid var(--primary); border-radius: 0 0.5rem 0.5rem 0; background: color-mix(in oklab, var(--primary) 8%, var(--bg-deep)); padding: 1.25rem 1.35rem; } + .pylog-guide .guide-takeaways ul { display: grid; gap: 0.5rem; margin: 0.8rem 0 0; padding-left: 1.1rem; list-style: disc; font-size: 15px; line-height: 1.6; color: var(--foreground); } + .pylog-guide .guide-takeaways li::marker { color: var(--primary); } /* One color per level: set --lvl on the element. */ .pylog-guide .lvl { color: color-mix(in oklab, var(--lvl) 85%, var(--foreground)); } diff --git a/apps/landing/src/pages/guides/sentry-pricing.astro b/apps/landing/src/pages/guides/sentry-pricing.astro index bc0bd5fa3d..46be446cdb 100644 --- a/apps/landing/src/pages/guides/sentry-pricing.astro +++ b/apps/landing/src/pages/guides/sentry-pricing.astro @@ -29,6 +29,7 @@ const toc = [ { depth: 2, slug: "plans", text: "Plans and prices" }, { depth: 3, slug: "business", text: "Team or Business" }, { depth: 3, slug: "seer", text: "Seer add-on" }, + { depth: 3, slug: "discounts", text: "Discounts" }, { depth: 2, slug: "free-plan", text: "The free plan" }, { depth: 3, slug: "free-limits", text: "Free plan limits" }, { depth: 3, slug: "self-hosted", text: "Self-hosted Sentry" }, @@ -281,14 +282,26 @@ const articleJsonLd = {
+
+

+ Before you add Sentry to an app, you want to know whether it stays free and what it costs once it doesn't. Sentry is an error tracking and performance monitoring service: a small library in your app reports crashes and slow requests, and Sentry groups them into issues with the stack trace attached. It's free for one developer: the Developer plan costs $0 for 5,000 errors and 5 million spans a month, and drops new errors past that until the month resets. Paid plans start at $29 a month and bill errors, spans, replays and logs above the plan's allowance at separate rates, so one noisy release can raise the bill. By the end you can estimate your own monthly bill and know which settings keep it down. +

+
+

Key takeaways

+
    +
  • Developer is $0 for one user, with 5,000 errors, 5M spans and 50 replays a month.
  • +
  • Team is $29 a month ($26 billed annually) and Business $89 ($80); both include 50,000 errors and 5M spans.
  • +
  • Business charges about twice the Team rate for each error and span above the included volume.
  • +
  • Reserved volume costs 20% less than pay-as-you-go for errors, spans, replays and attachments.
  • +
  • Once the pay-as-you-go budget runs out, new data is dropped until the billing cycle resets.
  • +
+
+
+

01 · Plans

Sentry plans and prices

-
-

Sentry charges a flat monthly price for the plan, then a separate price for each kind of data you send beyond what the plan includes. Errors, spans, session replays and logs each have their own allowance and their own rate.

-
-
@@ -328,6 +341,13 @@ const articleJsonLd = {

Seer, Sentry's AI debugging agent, is a separate subscription on Team and Business at $40 per active contributor per month. An active contributor is anyone who opens two or more pull requests in a month against a repository connected to Sentry with a Seer feature turned on. Seer is billed on its own line and does not draw from the pay-as-you-go budget.

+ +

Discounts

+
    +
  • Annual billing takes about 10% off: Team is $26 a month instead of $29, Business $80 instead of $89.
  • +
  • Open-source projects and nonprofits can apply for a sponsored account.
  • +
  • Sentry for Startups gives up to $5,000 in credits for 12 months to companies founded in the last 2 years, with under $5M raised and new to paying for Sentry.
  • +

Verified {verified} against sentry.io/pricing and Sentry's pricing docs, which round the per-unit prices.

@@ -649,6 +669,8 @@ const articleJsonLd = {
  • Sentry: Pricing (verified {verified})
  • Sentry docs: Pricing and billing
  • +
  • Sentry help: Do I qualify for a sponsored account? (verified 2026-10-31)
  • +
  • Sentry for Startups (verified 2026-10-31)
  • Sentry docs: Quota management
  • Sentry docs: Spike protection
  • Sentry docs: Session replay for JavaScript
  • @@ -674,7 +696,7 @@ const articleJsonLd = { .pricing-guide h2 { margin: 0 0 1.5rem; font-family: var(--font-display); font-size: clamp(1.75rem, 4vw, 2.5rem); font-weight: 500; line-height: 1.08; letter-spacing: -0.03em; color: var(--foreground); text-wrap: balance; } .pricing-guide h3 { margin: 3rem 0 0.8rem; font-family: var(--font-display); font-size: 1.2rem; font-weight: 550; line-height: 1.3; letter-spacing: -0.015em; color: var(--foreground); } .pricing-guide h4 { margin: 0; font-family: var(--font-display); font-size: 0.95rem; font-weight: 550; color: var(--foreground); } - .pricing-guide > section > p:not(.guide-eyebrow, .guide-kicker, .guide-note, .guide-verified), .pricing-guide .guide-answer p { margin: 0 0 1.15rem; font-size: 17px; line-height: 1.7; font-weight: 430; color: color-mix(in oklab, var(--foreground) 85%, var(--background)); } + .pricing-guide > section > p:not(.guide-eyebrow, .guide-kicker, .guide-note, .guide-verified) { margin: 0 0 1.15rem; font-size: 17px; line-height: 1.7; font-weight: 430; color: color-mix(in oklab, var(--foreground) 85%, var(--background)); } .pricing-guide .guide-note, .pricing-guide .guide-verified { margin: -0.75rem 0 1.5rem; font-size: 13px; line-height: 1.65; color: var(--muted-foreground); } .pricing-guide .guide-verified { margin-top: 0; } .pricing-guide strong { font-weight: 600; color: var(--foreground); } @@ -682,8 +704,9 @@ const articleJsonLd = { .pricing-guide pre { margin: 0; overflow-x: auto; border: 1px solid var(--border); border-radius: 0 0.5rem 0.5rem 0.5rem; background: var(--bg-deep); padding: 0.9rem 1.1rem; font-family: var(--font-mono); font-size: 12px; line-height: 1.75; color: var(--foreground); } .pricing-guide a:not(.guide-button) { color: var(--primary); text-decoration: underline; text-decoration-color: color-mix(in oklab, var(--primary) 42%, transparent); text-underline-offset: 3px; transition: color 150ms ease; } .pricing-guide a:not(.guide-button):hover { color: var(--foreground); } - .pricing-guide .guide-answer { margin: 2rem 0; border-left: 2px solid var(--primary); border-radius: 0 0.5rem 0.5rem 0; background: color-mix(in oklab, var(--primary) 8%, var(--bg-deep)); padding: 1.25rem 1.35rem; } - .pricing-guide .guide-answer p { margin: 0; font-size: 16px; line-height: 1.7; color: var(--foreground); } + .pricing-guide .guide-takeaways { margin: 2rem 0 0; border-left: 2px solid var(--primary); border-radius: 0 0.5rem 0.5rem 0; background: color-mix(in oklab, var(--primary) 8%, var(--bg-deep)); padding: 1.25rem 1.35rem; } + .pricing-guide .guide-takeaways ul { display: grid; gap: 0.5rem; margin: 0.8rem 0 0; padding-left: 1.1rem; list-style: disc; font-size: 15px; line-height: 1.6; color: var(--foreground); } + .pricing-guide .guide-takeaways li::marker { color: var(--primary); } .pricing-guide .guide-kicker { margin: 0; font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--primary); } .pricing-guide .guide-list { margin: 0 0 1.5rem; padding-left: 1.2rem; list-style: disc; font-size: 16px; line-height: 1.7; color: color-mix(in oklab, var(--foreground) 85%, var(--background)); } .pricing-guide .guide-list li + li { margin-top: 0.35rem; }