Skip to content

feat: Content analytics — Prometheus counter + OTel span attributes #186

@khaines

Description

@khaines

Summary

BlogFlow's HTTP metrics use low-cardinality route patterns (GET /posts/{slug}) for system health, but cannot answer "which posts are popular?" or "what content gets the most traffic?".

Proposed Solution

Two complementary, cloud-agnostic signals:

A. Prometheus counter

blogflow_content_views_total{type, slug} incremented on every successful content serve. Enables PromQL queries like "top 10 posts this week".

Labels:

  • type: post, page, tag, list, home
  • slug: actual slug/tag for posts/pages/tags; empty for list/home

Cardinality: ~1 series per content item (500 posts → 500 series — well within Prometheus comfort zone).

C. OTel span attributes

Added to the existing otelhttp request span:

Attribute Type Example
content.type string post
content.slug string hello-world
content.title string Hello World
content.tags string[] ["go","blog"]

Works with any OTel-compatible backend (Jaeger, Tempo, Zipkin, Grafana Cloud, etc.).

Implementation

  • New internal/server/handlers/content_metrics.go with counter + RecordContentView() helper
  • Wire to all 6 content handlers (PostHandler, PageHandler, TagHandler, PostsListHandler, ListHandler, HomeHandler)
  • Zero config — lights up automatically when content is served
  • Unit tests for counter increments and span attribute population

Acceptance Criteria

  • blogflow_content_views_total counter increments on each content serve
  • OTel span attributes populated for all content requests
  • Only recorded on successful content lookup (no 404 pollution)
  • Unit tests pass
  • go test ./... passes

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions