今日已更新 339 条资讯 | 累计 19899 条内容
关于我们

标签:#logging

找到 7 篇相关文章

开发者

How I shipped structured JSON logging + Prometheus metrics with zero new dependencies

How I shipped structured JSON logging + Prometheus metrics with zero new dependencies I almost added structlog and prometheus_client to my pyproject.toml . Then I read what they actually do. Both libraries are excellent. structlog is the right call when you have a 30-engineer team shipping 50 services. prometheus_client is the right call when you have five teams of consumers scraping different metrics. For a single-author Python project with one process and one user, both are over-engineered. The 80 lines of code I would have pulled in, I can write in 200. The result: zero new runtime dependencies, full control over the output, and a smaller pip install footprint for every user. Here is what I did instead. The minimum useful observability surface A small Python service needs four things, in order of importance: Every log line is one JSON object. (No parsing for downstream tools.) Every request has a trace id. Every log line in that request carries the same trace id. (So you can grep by id and see the whole story.) Every log line goes to stderr. (So journald , Docker, and kubectl logs all see it without any extra configuration.) Every metric is exposed in Prometheus text format at a stable URL. structlog gives you #1, #2, #3 with a lot of flexibility. prometheus_client gives you #4 with a lot of flexibility. Both are about 16 MB of transitive dependencies combined. For a service that runs in a single process and exports maybe 20 metric names, the libraries are doing more work than the project. The 80-line JsonFormatter The custom logging formatter is the simplest part. The whole thing is here: import json import logging from contextvars import ContextVar from datetime import datetime , timezone _trace_id_var : ContextVar [ str | None ] = ContextVar ( " trace_id " , default = None ) class JsonFormatter ( logging . Formatter ): def format ( self , record : logging . LogRecord ) -> str : payload = { " ts " : datetime . now ( tz = timezone . utc ). isoformat (), " level

2026-07-13 原文 →
AI 资讯

Logging — Request Logging

Request logging: vì sao mỗi log line phải có request id, và structured log cứu debug thế nào khi có sự cố production Request logging không phải là in console.log('got a request') cho vui. Nó là dấu vết duy nhất còn lại khi một request đã đi qua service, đi qua vài downstream, gặp lỗi, và bị đóng socket. Nếu log không có gì để nối lại các dòng thuộc cùng một request — không có requestId , không có traceId — thì log của một service RPS trung bình biến thành một mớ text xen kẽ giữa hàng chục request đồng thời, và câu hỏi "request X đã đi tới đâu, fail ở service nào" trở thành không trả lời được. Structured log (mỗi dòng là một JSON object với field cố định) + một correlation id truyền qua toàn bộ pipeline chính là cái làm log có thể query được, thay vì grep mù. Hai framework Express và Fastify tiếp cận khác nhau: Fastify tích hợp pino sẵn và tự sinh req.id , Express phải tự dán qua pino-http hoặc middleware tay. Nhưng cả hai đều vỡ theo cùng một kiểu khi correlation id bị đứt giữa các service. Cơ chế hoạt động Ba miếng ghép: (1) một structured logger — thường là pino trong ecosystem Node vì nó ghi NDJSON và có async destination, (2) một cơ chế sinh/nhận requestId , (3) một cách propagate id đó qua async work và qua HTTP call sang service khác. pino là JSON logger tối giản: mỗi lời gọi logger.info({...}, 'message') xuất một dòng NDJSON ra một WritableStream (mặc định là stdout). Log level là số ( trace=10, debug=20, info=30, warn=40, error=50, fatal=60 , theo pino docs), và có child logger — logger.child({ reqId }) tạo một logger mới bind sẵn các field, mọi log line từ child đều có reqId mà không phải truyền tay. Với Fastify , chỉ cần logger: true là có pino và request logging tự động — Fastify sinh request.id (mặc định là monotonic counter, đổi được qua option genReqId ) và log một cặp dòng "incoming request" / "request completed" cho mỗi request. Trong handler, request.log là child logger đã bind reqId : import Fastify from ' fastify ' import crypto from ' node:crypto

2026-07-08 原文 →
AI 资讯

Write-Ahead Logging — WAL Fundamentals

WAL: vì sao Postgres bắt buộc ghi log trước data file, và lý do pg_wal/ đầy đĩa làm cluster ngừng nhận write WAL (Write-Ahead Log) là cơ chế durability lõi của Postgres: mọi thay đổi đối với heap, index, free-space map, visibility map đều phải được ghi xuống WAL và fsync trước khi data file tương ứng được phép flush ra đĩa . Nguyên tắc này, mô tả trong Postgres docs chương "Reliability and the Write-Ahead Log", là cái cho phép một transaction đã COMMIT thoả ACID-D dù OS crash hoặc mất điện ngay sau đó. Dev gặp WAL trong việc thật không phải vì cú pháp khó: gặp khi pg_wal/ đầy đĩa do một replication slot bị quên dọn, Postgres dừng nhận write với PANIC: could not write to file ... No space left on device , hoặc khi crash recovery sau OOM kéo mười mấy phút làm health check fail và load balancer cắt traffic. Cơ chế hoạt động Postgres không ghi thẳng vào data file mỗi khi có INSERT / UPDATE . Trang 8KB (heap page, index page) sống trong shared_buffers ; mỗi thay đổi tạo ra một WAL record mô tả delta đó (record type, relfilenode, block number, payload), append vào wal_buffers — một vùng shared memory nhỏ trước khi xuống đĩa. Tại thời điểm COMMIT , backend gọi XLogFlush() để write + fsync WAL tới hết byte chứa commit record; chỉ sau khi fsync trả về, Postgres mới ghi commit bit vào pg_xact và reply OK về client. Data page bẩn ở lại trong shared_buffers ; checkpointer sẽ flush chúng ra data file sau, không gắn với từng commit. WAL được tổ chức thành segment file kích thước cố định trong $PGDATA/pg_wal/ , mặc định 16MB mỗi segment (cấu hình lúc initdb --wal-segsize ). Vị trí trong WAL là LSN (Log Sequence Number) — số 64-bit, in dạng XXXX/XXXXXXXX , thực chất là byte offset từ đầu WAL của cluster. LSN tăng đơn điệu và là "đồng hồ" duy nhất Postgres tin cậy cho thứ tự ghi. -- Quan sát LSN tiến lên sau mỗi ghi SELECT pg_current_wal_lsn (); -- vd: 0/1A2B3C40 INSERT INTO t SELECT g FROM generate_series ( 1 , 1000 ) g ; SELECT pg_current_wal_lsn (); -- 0/1A2BE018 SELECT pg_wal_ls

2026-07-07 原文 →
AI 资讯

I Run a 21-Article Gaming Blog With Zero Coding — Here's My Tech Stack

I started a gaming guide blog six weeks ago. Twenty-one articles later, it's getting traffic from Google, I have four affiliate programs set up, and I have never written a single line of code. This is not a "how to make money blogging" post. This is a practical breakdown of the tools, the workflow, and the mistakes I made so you can skip them. The blog is yxgonglue.com. It covers PC and console game guides — GTA VI pre-order comparisons, VPN setups for gaming, cloud gaming platform rankings, extraction shooter loot guides. Niche stuff. The kind of content people search for when they have a specific problem. Here is the stack that runs it. THE STACK WordPress + Kadence Theme Hosted on a standard shared hosting plan. Kadence is a free WordPress theme that loads fast and does not fight you. No page builder. No Elementor. Just the block editor and Kadence blocks for tables and formatting. The biggest lesson here: your theme does not matter as much as your content structure. Pick something lightweight. Stop theme-shopping. Start writing. Yoast SEO The free version. It gives you a red/yellow/green score for each post based on keyphrase density, subheading distribution, link count, and meta length. Is it perfect? No. Is it a useful checklist for someone who does not do SEO for a living? Absolutely. One thing Yoast taught me the hard way: Custom HTML blocks are invisible to the plugin. If you paste your article into a Custom HTML block, Yoast reads zero words, zero links, zero headings. Everything turns red. Use the regular editor. If you need a table, use a table block. Keep it simple. Google Search Console This is where you see what people actually searched before they clicked your article. The gap between what you think people search for and what they actually search for is enormous. Search Console closes that gap. Submit every new post URL manually. It takes ten seconds. Do not wait for Google to discover your site on its own. THE CONTENT WORKFLOW One Article Per Day Tw

2026-06-28 原文 →
AI 资讯

When should you publish a dev post? I counted, and JP vs EN are mirror images

Let me confess something a little creepy. I have a habit of peeking at other people's dev posts. Not stealing the writing — relax. I run a tiny read-only job that fetches the public pages on dev.to, Zenn, and Qiita and counts only the boring parts: titles, post times, like counts. Who published what, at what hour, and how far it traveled. Then it tallies the lot. The reason is petty: my own posts weren't landing. The content is already in my hands — so I wanted to know how much the rest, the when and how you publish , actually moves the needle. By the numbers, not by gut. So I counted across three platforms. And the conditions that make a post fly turned out to be roughly mirror images between Japan (Zenn / Qiita) and the English-speaking world (dev.to). Here's the story. First, my most important disclaimer This post is full of numbers, so let me put up a guardrail before any of them. This is correlation, not causation . A result like "weekend posts don't do well" could mean the weekend itself is bad — or it could mean people who post on weekends are just dashing something off on the side. The data can't separate those. Please read it that way. Also, I only keep aggregate numbers I computed myself . I don't store or reuse anyone's article body (read-only GET, count the features, throw the page away). I peek, but only at the overall shape . Nobody gets singled out here. With that out of the way — four findings I enjoyed. 1. The best hour to publish is just your readers' time zone This one came out cleanest. On Qiita , posts published in the morning win (+32pt in the GOOD group). Midday is +14pt. Evening is -32pt, late night -14pt. Zenn likes midday too (+27pt). Late night is -15pt. dev.to is the exact opposite. Late night Japan time scores +7pt — Japanese evening is actually weak. The trick is obvious once you see it. dev.to's readers are English-speaking, mostly US. Late night in Japan is the US working day. Zenn and Qiita readers are in Japan, so the Japanese morni

2026-06-22 原文 →
AI 资讯

Quill vs spdlog: Which C++ Logger Is Better for Low-Latency Applications?

Logging has a habit of ending up in the places you care about most. It starts as a few lines for visibility. Then those lines appear in request handling, market-data processing, matching loops, telemetry pipelines, and other code where predictable latency matters. At that point, a log statement is no longer just observability. It is work running on the same thread you are trying to keep fast. A line like this can look harmless: LOG_INFO ( logger , "order_id={} price={}" , order_id , price ); The important question is what happens before the caller continues . Does it evaluate expensive arguments? Format text? Copy buffers? Allocate? Contend with other producer threads? Wait for queue space? For many applications, those costs are acceptable. For latency-sensitive systems, they are part of the latency budget . spdlog is one of the best-known C++ logging libraries and a strong general-purpose choice. It is mature, easy to use, and has a broad feature set. Quill was designed for a narrower problem: How little work can a C++ logger leave on the caller thread while still producing rich, human-readable logs? That is the lens for this comparison. The interesting difference is not which library has more features. It is where each library chooses to spend work. At a Glance Area spdlog async Quill User-message formatting Producer thread Backend thread Producer handoff Shared thread-pool queue Per-thread SPSC queue Arguments for runtime-disabled levels Evaluated if the level was not compiled out Skipped by the macro-level runtime check Native synchronous mode Yes No Backend workers Configurable thread pool Single backend worker Primary focus General-purpose flexibility Low producer-side latency These differences do not make one library universally better. They make each library better suited to different workloads. Async Logging Is Not One Design "Async logging" often means "file I/O happens on another thread." That is useful, but it is not enough to describe the cost paid by t

2026-06-19 原文 →
AI 资讯

A Domain Logger Port: Decoupling From PSR-3 Without Losing Context

Book: Decoupled PHP — Clean and Hexagonal Architecture for Applications That Outlive the Framework Also by me: Thinking in Go (2-book series) — Complete Guide to Go Programming + Hexagonal Architecture in Go My project: Hermes IDE | GitHub — an IDE for developers who ship with Claude Code and other AI coding tools Me: xgabriel.com | GitHub You open a use case that places an order. Near the top of the constructor, alongside the repositories and the payment gateway, sits a Psr\Log\LoggerInterface . The method body calls $this->logger->info(...) three times. It looks harmless. It is the most common way framework concerns leak back into a domain you spent weeks keeping clean. PSR-3 is a fine standard. Monolog is the default implementation in most PHP projects, and it earns that spot. The problem is not the library. The problem is where you point it. When LoggerInterface is a constructor argument in your application layer, your use case now depends on a package whose surface area you do not control, whose log levels you may not want, and whose context conventions are someone else's. The dependency arrow points the wrong way. What PSR-3 drags in Psr\Log\LoggerInterface is eight level methods plus a generic log() . The level taxonomy comes from RFC 5424 syslog: emergency , alert , critical , error , warning , notice , info , debug . That is a system-administration vocabulary. Your domain does not speak it. When a use case calls $this->logger->warning('payment retry') , you have to ask: is a retry a warning or a notice ? The answer is an infrastructure judgment call wearing a domain costume. The method signature also accepts an arbitrary array $context and a string|Stringable $message with {placeholder} interpolation. None of that is something your application code should be deciding. <?php declare ( strict_types = 1 ); namespace App\Application\Order ; use Psr\Log\LoggerInterface ; final readonly class PlaceOrder { public function __construct ( private OrderRepository $ord

2026-06-14 原文 →