---
title: "Alana göre arayabileceğin log formatı ve log seviyeleriyle yapılandırılmış loglama"
description: "Yapılandırılmış loglama her değeri bir cümlenin içine değil, kendi alanına koyar. 1 siparişi 3 yolla LogBrew'a gönderdik ve hangi log formatını order_id ile yeniden bulabildiğini gösteriyoruz."
canonical: "https://logbrew.co/tr/guides/structured-logging"
last_updated: "2026-11-10"
---

# Alana göre arayabileceğin log formatı ve log seviyeleriyle yapılandırılmış loglama

Yapılandırılmış loglama her değeri bir cümlenin içine değil, kendi alanına koyar. 1 siparişi 3 yolla LogBrew'a gönderdik ve hangi log formatını `order_id` ile yeniden bulabildiğini gösteriyoruz.

10 Kasım 2026 tarihinde Python 3.13.5 ve logbrew-sdk 0.1.29 ile test edildi

[Furkan Erday](https://github.com/furkanerday) tarafından. Furkan Erday, LogBrew'un kurucusu. LogBrew'u her gün Claude Code ve Codex ile geliştiriyor.

Canonical: https://logbrew.co/tr/guides/structured-logging

## `order_id` ile yeniden bulabildiğin log satırı

| id nereye gitti | Metin araması | Alan filtresi |
| --- | --- | --- |
| Mesaj metninin içinde | Bulundu | Bulunamadı |
| `extra={}` alanlarında | Bulunamadı | Bulundu |
| `extra={}` içindeki bir dict'te | Bulunamadı | Bulunamadı |

1 siparişi 3 yolla Python handler'ı üzerinden gönderdik, sonra aradık. Dolu kupa, aramanın satırı bulduğu anlamına gelir.

## Filtreleyebileceğin bir log formatı seç

### Mesajı sabit tut, değerleri alanlara koy

Bir alan adını ve türünü korur. Mesaj metninin içindeki bir değer yalnızca bir alt dizedir. Python'da alanları `extra={}` içinde geç, mesaj her sipariş için aynı kalır.

```bash
log.info("order paid", extra={"order_id": "ord_42", "amount_cents": 1999})
```

### Logu bir program okuyacaksa JSON satırları yaz

Bir `Formatter` alt sınıfı her kaydı satır başına 1 JSON nesnesine çevirir, standart alanlar ve her `extra` değeriyle birlikte. Bir log toplayıcı satırı regex olmadan ayrıştırır.

```bash
import json
import logging

RECORD_FIELDS = set(vars(logging.LogRecord("", 0, "", 0, "", (), None))) | {"message", "asctime"}


class JsonFormatter(logging.Formatter):
    def format(self, record: logging.LogRecord) -> str:
        line = {
            "time": self.formatTime(record, "%Y-%m-%dT%H:%M:%S%z"),
            "level": record.levelname,
            "logger": record.name,
            "message": record.getMessage(),
        }
        line.update({k: v for k, v in vars(record).items() if k not in RECORD_FIELDS})
        if record.exc_info:
            line["exception"] = self.formatException(record.exc_info)
        return json.dumps(line)


handler = logging.StreamHandler()
handler.setFormatter(JsonFormatter())
logging.basicConfig(level=logging.INFO, handlers=[handler])
log = logging.getLogger("taproom")

log.info("order paid", extra={"order_id": "ord_42", "amount_cents": 1999})
log.warning("keg below 10%", extra={"keg": "ipa", "percent": 8})
```

Çıktı

```text
{"time": "2026-11-10T08:34:04+0300", "level": "INFO", "logger": "taproom", "message": "order paid", "order_id": "ord_42", "amount_cents": 1999}
{"time": "2026-11-10T08:34:04+0300", "level": "WARNING", "logger": "taproom", "message": "keg below 10%", "keg": "ipa", "percent": 8}
```

### Alanları LogBrew'a gönder

`LogBrewLoggingHandler` her kaydı `extra` değerleri alan olarak gönderir. Aynı siparişi 3 yolla gönderdik, mesaj metninin içinde, `extra` alanları olarak ve `extra` içinde bir dict olarak.

```bash
import logging
import os

from logbrew_sdk import HttpTransport, LogBrewClient, LogBrewLoggingHandler

client = LogBrewClient.create(api_key=os.environ["LOGBREW_SERVER_API_KEY"])
transport = HttpTransport()
log = logging.getLogger("taproom")
log.addHandler(LogBrewLoggingHandler(client, transport, metadata={"service": "taproom"}))
log.setLevel(logging.INFO)

logging.getLogger("taproom.text").info("order %s paid, %d cents", "ord_42", 1999)
logging.getLogger("taproom.fields").info(
    "order paid", extra={"order_id": "ord_42", "amount_cents": 1999}
)
logging.getLogger("taproom.nested").info(
    "order paid", extra={"order": {"id": "ord_42", "amount_cents": 1999}}
)

response = client.flush(transport)
print("HTTP", response.status_code, "accepted", response.accepted_events, "logs")
```

Çıktı

```text
HTTP 200 accepted 3 logs
```

### Satırı alana göre yeniden bul

`GET /api/logs` alan yolu, tür, operatör ve değerden oluşan `attribute_filters` alır. `order_id` filtresi yalnızca `extra` ile gönderilen satırı buldu. `extra` içindeki dict atıldı, çünkü handler yalnızca metinleri, sayıları, boolean değerleri ve `None` değerini tutar.

```bash
curl -sS -G "https://api.logbrew.co/api/logs" \
  -H "Authorization: Bearer $LOGBREW_TOKEN" \
  --data-urlencode "project_id=$LOGBREW_PROJECT" \
  --data-urlencode "since=2026-11-10T05:31:33Z" \
  --data-urlencode 'attribute_filters=[{"path":"/metadata/order_id","type":"string","operator":"eq","value":"ord_42"}]' \
  | jq -c '.[] | {message, order_id: .attributes.metadata.order_id}'
```

Çıktı

```text
{"message":"order paid","order_id":"ord_42"}
```

## Log seviyelerini her serviste aynı şekilde kullan

### Canlı ortamda 4 seviye kullan

Olan biten için `info`, ters gidip ele alınan için `warning`, başarısız istek ya da iş için `error`, servisi durduran için `critical`. `debug` seviyesini yerel çalıştırmalara sakla. LogBrew handler'ı DEBUG kayıtlarını `info` olarak gönderir.

### Seviyeyi başlangıçta 1 kez ayarla

Seviyeyi ortam değişkeninden oku, böylece 1 sunucu DEBUG'da çalışırken geri kalanı INFO'da kalır. Python'da bunu `logging.basicConfig(level=os.environ.get("LOG_LEVEL", "INFO"))` yapar.

### Sayıları sayı olarak logla

`amount_cents: 1999` türünü korur, bu yüzden `amount_cents >= 1000` filtresi onu bulur. `amount_cents: "1999"` değerini metin olarak da gönderdik, sayı filtresi o satırı atladı.

```bash
curl -sS -G "https://api.logbrew.co/api/logs" \
  -H "Authorization: Bearer $LOGBREW_TOKEN" \
  --data-urlencode "project_id=$LOGBREW_PROJECT" \
  --data-urlencode "since=2026-11-10T05:31:33Z" \
  --data-urlencode 'attribute_filters=[{"path":"/metadata/amount_cents","type":"number","operator":"gte","value":1000}]' \
  | jq -c '.[] | {message, amount_cents: .attributes.metadata.amount_cents}'
```

Çıktı

```text
{"message":"order paid","amount_cents":1999}
```

## Test ederken gördüklerimiz

1 siparişi 3 yolla Python handler'ı üzerinden gönderdik, sonra LogBrew API'siyle aradık. Metin araması `search=ord_42` 3 satırdan 1'ini buldu, id'si mesajın içinde olanı.

`order_id = ord_42` filtresi 1 satır buldu, `extra={"order_id": "ord_42"}` ile gönderileni. `amount_cents >= 1000` filtresi aynı satırı buldu, çünkü handler 1999'u sayı olarak tuttu.

`extra={"order": {...}}` ile gönderilen satır hiçbir şeyle eşleşmedi. Handler `extra` içinden metinleri, sayıları, boolean değerleri ve `None` değerini gönderir, dict ya da listeyi atlar.

```bash
curl -sS -G "https://api.logbrew.co/api/logs" \
  -H "Authorization: Bearer $LOGBREW_TOKEN" \
  --data-urlencode "project_id=$LOGBREW_PROJECT" \
  --data-urlencode "since=2026-11-10T05:31:33Z" \
  --data-urlencode "search=ord_42" \
  | jq -c '.[] | {message, order_id: .attributes.metadata.order_id}'
```

Çıktı

```text
{"message":"order ord_42 paid, 1999 cents","order_id":null}
```

## Düz metin ile JSON log formatı

Düz bir `%(message)s` formatı her `extra` değerini atar. Aşağıdaki satır sipariş id'si olmadan `INFO order paid` ile biter, bu yüzden kimse siparişi sonradan bulamaz.

Bir JSON satırı alanları ve türlerini korur, log toplayıcı onu regex olmadan ayrıştırır. İnsan daha zor okur, bu yüzden mesajı kısa, alan adlarını sabit tut.

Python'da yerleşik bir JSON formatter yok. python/cpython#77691 2018'de bir tane istedi ve kapatıldı, çünkü dokümantasyon zaten nasıl yazılacağını gösteriyor. Yukarıdaki 15 satırlık `Formatter` o tarifin kendisi.

```bash
import logging

logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
log = logging.getLogger("taproom")

log.info("order paid", extra={"order_id": "ord_42", "amount_cents": 1999})
```

Çıktı

```text
2026-11-10 08:34:04,955 INFO order paid
```

## LogBrew ne kaydeder

Her log seviyesini, logger adını ve `extra` içindeki her ilkel alanı, artı handler'daki `metadata={}` alanlarını korur. API alan yolu, tür ve operatöre göre filtreler. Metin `eq`, `ne`, `contains` ve `starts_with`, sayılar `gt`, `gte`, `lt` ve `lte` alır.

LogBrew adında `password`, `secret`, `token`, `cookie` ya da `authorization` geçen bir alanı dizine eklemez, bu yüzden bir filtre onu asla bulmaz. Gizli bilgileri yine de log satırlarının dışında tut.

Bir trace içinde gönderilen log, trace ve span id'lerini taşır, bu yüzden `order_id` filtresi satırı üreten isteğe götürür.

## Sık sorulan sorular

### Yapılandırılmış loglama nedir?

Her değerin cümle içindeki kelimeler yerine türü olan adlandırılmış bir alan olduğu loglama, JSON olarak ya da log kaydındaki alanlar olarak. Arama aracı o zaman alt dizeye değil alana göre filtreler.

### Log seviyeleri sırasıyla nedir?

DEBUG, INFO, WARNING, ERROR, CRITICAL, Python'da 10'dan 50'ye sayılarla. INFO'ya ayarlanmış bir logger INFO ve üstünü geçirir, DEBUG'ı atar.

### JSON mu düz metin mi loglamalıyım?

Satırları bir program okuyacaksa JSON, toplayıcı, dosya ya da arama aracı gibi. Terminali yalnızca bir insan okuyacaksa düz metin. İkisinde de aynı alanları tut.

### Python log satırına alan nasıl eklerim?

Log çağrısına `extra={"order_id": "ord_42"}` geç. Standart formatter extra alanları yok sayar. JSON formatter ya da LogBrew handler'ı onları tutar.

### LogBrew'da logları alana göre arayabilir miyim?

Evet. `GET /api/logs` en fazla 4 `attribute_filters` alır, her biri alan yolu, tür ve `eq` ya da `gte` gibi bir operatörle.

## Loglarını istediğin alana göre filtrele

LogBrew logladığın her alanı korur ve satırı ait olduğu trace ve sorunun yanında alana göre yeniden bulur. Cömert ücretsiz planla başla, kart gerekmez.

[Ücretsiz başla](https://logbrew.co/tr)

## Kaynaklar

- [Python docs, Logging Cookbook](https://docs.python.org/3/howto/logging-cookbook.html)
- [Python docs, LogRecord attributes](https://docs.python.org/3/library/logging.html#logrecord-attributes)
- [python/cpython#77691](https://github.com/python/cpython/issues/77691)

## Ajanlar ve Python için diğer rehberler

- [Claude Code ve Codex'e MCP sunucusu ekle](https://logbrew.co/tr/guides/mcp-server-claude-code-codex)
- [Claude Code ve Codex'te AGENTS.md kullan](https://logbrew.co/tr/guides/agents-md)
- [Claude overloaded 529 ve rate limit 429 hatalarını çöz](https://logbrew.co/tr/guides/claude-overloaded-rate-limit-error)
- [Python loglamayı doğru log seviyeleri ve istisna yakalamayla kur](https://logbrew.co/tr/guides/python-logging)
- [Claude Code, Codex, JavaScript ve Python'daki hataları çöz](https://logbrew.co/tr/guides)
