Nabız Hub için Python raporlayıcı: sunucu hataları, yavaş istekler, canlılık.
Bağımlılık yok. Build adımı yok. Python 3.9+.
Kardeş paketler: allturko/nabiz (Laravel), @allturko/nabiz-node (Node),
t.js (tarayıcı, hub reposunda resources/sdk/t.js).
Bu paket yalnızca sunucu tarafını kapsar. Tarayıcı hataları hub'dan servis edilen
t.js ile toplanır; o dosya bilinçli olarak pakete taşınmadı — hosted olması bir
düzeltmenin dakikalar içinde tüm sitelere yayılmasını sağlıyor, paket olsaydı her
düzeltme için bütün projelerin yeniden dağıtılması gerekirdi.
Toplanmayanlar — yapılandırmayla dahi açılamaz:
IP adresi · User-Agent · istek gövdesi · query string değerleri (yalnızca yol) · oturum verisi · çerez · ham SQL literalleri
pip install git+https://github.com/AllturkoGit/nabiz-python.git.env dosyasına — kardeş paketlerle aynı değişken isimleri:
NABIZ_ENABLED=true
NABIZ_URL=https://monitor.ornek.com
NABIZ_KEY=proje-anahtari
NABIZ_SECRET=<panelden alınan 64 karakterlik secret>
NABIZ_ENV=productionfrom flask import Flask
from nabiz.flask import NabizFlask
app = Flask(__name__)
NabizFlask(app)Tek satır şunları kurar: yakalanmamış istisnalar (teardown_request), 5xx ve yavaş
istekler (after_request), süreç düzeyi kancalar (sys.excepthook,
threading.excepthook) ve 8 saatlik canlılık isteği.
- Tek arıza, tek kayıt: hata veren istek yalnızca stack'li
exceptionaçar; aynı istek için ayrıcahttp_5xxgönderilmez (0.1.1+). - Kendi hata işleyiciniz varsa:
@app.errorhandler(Exception)ya daerrorhandler(500)tanımlıysa hata yine stack'iyle gelir. İşleyici 4xx dönerse gönderilmez. Eskiden bu durumda hata kayboluyor, yalnızca stack'sizhttp_5xxgeliyordu. abort(4xx)gönderilmez: bilinçli yanıt, arıza değil.- Kurulum sırası serbest:
NabizFlask(app)önce,nabiz.init(...)sonra çağrılabilir; istek kancaları da süreç kancaları da (sys.excepthook,threading.excepthook) güncel raporlayıcıyı çağrı anında çözer. Kurulumda yapılandırma yoksa canlılıkinit(...)çağrılınca başlar. - İki kez kurmak zararsız: aynı uygulamada ikinci
NabizFlask(app)hiçbir şey eklemez; süreç kancaları süreç başına bir kez kurulur. - Uygulamayı düşürmez: kurulum (bozuk ya da UTF-8 olmayan
.envdahil) hiçbir koşulda hata fırlatmaz. - Süreç kancalarını kapatmak:
NabizFlask(app, hook_process_errors=False)yalnızca istek kancalarını kurar.
# settings.py
MIDDLEWARE = [
"nabiz.django.NabizMiddleware", # listenin başına yakın
# ...
]Ara katman yavaş ve 5xx istekleri ölçer, yakalanmamış istisnayı stack'iyle gönderir.
Hata iki yoldan görülür: Django'nun istisnayı 500'e çevirirken yolladığı
got_request_exception sinyali (görünümün yanında alttaki ara katmanlardan çıkan
hatalar da) ve process_exception. Kurallar Flask'la aynı:
- Tek arıza, tek kayıt; hata veren istek için ayrıca
http_5xxaçılmaz. - 4xx gönderilmez:
Http404,PermissionDenied,BadRequest,SuspiciousOperation. - Rota deseni gider:
/urun/<int:urun_id>/, gerçek id değil.re_pathdesenlerinde baştaki^ve sondaki$atılır. - Hata yutulmaz:
process_exceptionNonedöner; Django'nun 500 sayfası vehandler500olduğu gibi çalışır. - Süreç kancaları ilk kurulumda bir kez açılır; kapatmak için
NABIZ_HOOK_PROCESS = False.
from fastapi import FastAPI
from nabiz.asgi import NabizASGIMiddleware
app = FastAPI()
app.add_middleware(NabizASGIMiddleware)Starlette'te aynı satır (Starlette(middleware=[Middleware(NabizASGIMiddleware)]) de
olur). Başka bir ASGI uygulaması doğrudan sarılabilir: app = NabizASGIMiddleware(app).
Saf ASGI ara katmanıdır; Starlette/FastAPI import anında yüklenmez.
- Tek arıza, tek kayıt; 4xx
HTTPExceptionve doğrulama hataları (422) gönderilmez. BilinçliHTTPException(5xx)stack'sizhttp_5xxolarak düşer. - Rota deseni gider:
/urun/{urun_id};include_routeröneki veMountyolu desene eklenir. - Kendi hata işleyiciniz varsa:
@app.exception_handler(Exception)hatayı yine bizim katmanımızdan geçirir. Belirli bir sınıfa bağlı işleyici (@app.exception_handler(ValueError)) 5xx dönerse hata yine stack'iyle gelir, 4xx dönerse gönderilmez. Ara katman sırası fark etmez (add_middlewareya damiddleware=[...]içinde herhangi bir yer). Elle sarılan uygulamada (NabizASGIMiddleware(app)) Starlette yığınını ilk istekte kurduğu için bu ilk istekten sonra devreye girer; o ilk istekte 5xx stack'sizhttp_5xxolur. - Süre yanıtın son baytında durur:
BackgroundTasksve yanıt sonrası işler yavaş istek sayılmaz. Uzun akış (SSE, büyük indirme) son parçaya kadar sürer ve yavaş sayılabilir. - İç içe katman tek kayıt açar:
Mountedilen alt uygulamada daNabizASGIMiddlewarevarsa istek yalnızca dıştakinde ölçülür. - Hata yutulmaz: raporlanır ve yeniden fırlatılır; lifespan ve websocket olduğu gibi geçer.
- Süreç kancalarını kapatmak:
app.add_middleware(NabizASGIMiddleware, hook_process_errors=False).
import nabiz
nabiz.hook_process() # kancalar + canlılık
nabiz.report(error) # elle bildirim
nabiz.init(ignore=(KeyboardInterrupt, "BenimBeklenenHatam")) # sınıf ya da ad
nabiz.start_heartbeat() # yalnızca canlılık (hook_process zaten başlatır)
nabiz.stop_heartbeat()init() ortam değişkenlerini okur; verilen argümanlar onları ezer. Çağrılmazsa ilk
kullanımda kendiliğinden kurulur.
nabiz-durumBu adım atlanmamalı. Paketin en pahalı arıza biçimi sessiz çalışmamadır: secret
eksik kopyalanmışsa hiçbir şey patlamaz, hiçbir log düşmez — hub geçersiz imzaya da
204 döner. Kurulum aylarca çalışmıyor olabilir ve o sessizlik "sorun yok" sanılır.
nabiz-durum --test # gerçek bir sınama olayı — panelde hata olarak görünür
nabiz-durum --nabiz # yalnızca canlılık isteği — panele hata düşürmez--test tek bir kurulumu doğrularken doğru seçim. Onlarca kurulumu gezen bir
güncelleme döngüsünde --nabiz kullanılır — --test orada panele onlarca sahte hata
bırakır, yani izleme aracı kendi gürültüsünü üretir.
Verinin gerçekten ulaştığı yalnızca hub panelinden doğrulanır: proje satırındaki
bağlantı durumu Bağlı görünmelidir. Komut bunu kendi başına söyleyemez, çünkü hub
geçerli ile geçersiz imzayı dışarıya aynı yanıtla karşılar.
Komut ayrıca şunları gösterir:
Sürüm etiketi— olaylara eklenecekreleaseve nereden bulunduğu:abc123def456 (kaynak: .git); kaynakNABIZ_RELEASE, bir CI/PaaS değişkeninin adı,.gitya dayok. Ayrıntı: Sürüm etiketi.Güncel sürüm— GitHub etiketlerindeki en yeni kararlı sürüm (paket PyPI'da değil). Kurulu sürümden yeniyse birGüncelleme var: pip install -U --force-reinstall "allturko-nabiz @ git+…@vX.Y.Z"satırı yazılır; bu bir uyarıdır, çıkış kodunu değiştirmez. Ağ yoksa ya da GitHub hız sınırına takıldıysadenetlenemediyazar (2 sn zaman aşımı). Ağa hiç çıkılmaması içinNABIZ_DURUM_CEVRIMDISI=1(1,true,yes,on,evet; büyük/küçük harf fark etmez) — o durumdaGüncel sürümsatırı hiç yazılmaz.
| Değişken | Varsayılan | Açıklama |
|---|---|---|
NABIZ_ENABLED |
true |
false iken hiçbir veri gönderilmez |
NABIZ_URL |
— | Hub adresi (https) |
NABIZ_KEY |
— | Proje anahtarı |
NABIZ_SECRET |
— | 64 karakterlik imza secret'i |
NABIZ_ENV |
APP_ENV |
production · staging · local. Takma adlar çevrilir: prod/live → production, stage/stg/preprod/uat → staging, dev/development/test/testing → local. Tanınmayan değeri hub reddeder; teşhis komutu hata verir |
NABIZ_RELEASE |
kendiliğinden | Sürüm etiketi. Boşsa CI/PaaS commit değişkenlerinden ya da .git'ten bulunur — aşağıya bakın |
NABIZ_DURUM_CEVRIMDISI |
— | 1/true/yes/on/evet iken nabiz-durum güncelleme denetimi için ağa çıkmaz |
NABIZ_TIMEOUT |
2.0 |
Gönderim zaman aşımı, saniye. 100 ve üstü milisaniye sayılır — Node aynı adla ms bekliyor, 2000 yazan 2000 saniye beklemesin. Geçersiz, sıfır/eksi, NaN ya da sonsuz → 2 sn; sonuç 0.1–10 sn aralığına sıkıştırılır |
NABIZ_SLOW_REQUEST_MS |
1000 |
Yavaş istek eşiği |
Ortam değişkenleri os.environ ve .env / .env.local / .env.<APP_ENV>
dosyalarından okunur; süreç ortamı her zaman kazanır. Yalnızca NABIZ_ önekli
anahtarlar okunur.
NABIZ_RELEASE neredeyse hiçbir kurulumda doldurulmuyordu; hub bu yüzden bir hatanın
hangi deploy ile başladığını söyleyemiyordu. Deploy'larımız çoğunlukla sunucuda
git pull + gunicorn yeniden başlatma: yeni süreç açılışta commit'i kendisi okur, deploy
sonrası ilk hatada panel yeni sürümü görür. Etiket kurulumda bir kez çözülür (olay başına
değil); ilk dolu kaynak kazanır:
init(release=...)ile açıkça verilen değer.NABIZ_RELEASE— kırpılır, en çok 64 karakter, olduğu gibi.- Sırasıyla
GIT_COMMIT,GIT_SHA,COMMIT_SHA,SOURCE_VERSION,VERCEL_GIT_COMMIT_SHA,RENDER_GIT_COMMIT,HEROKU_SLUG_COMMIT,CI_COMMIT_SHA. 7–40 hane hex ise küçük harfle ilk 12 hane; değilse kırpılmış, en çok 64 karakter. - Çalışma dizinindeki git checkout'u:
.git/HEAD→ dal ref dosyası, yoksapacked-refs; ayrık HEAD'de sha'nın kendisi..gitbir dosyaysa (submodule vb.)gitdir:izlenir. Yalnızca geçerli 40 hane sha, küçük harfle ilk 12 hane.gitkomutu çalıştırılmaz, dosyalar okunur; okunamazsa sessizce vazgeçilir.ref:yalnızcarefs/altını gösterebilir,..içeremez. Git worktree'leri (commondir) desteklenmez — dal ref'i ortak dizinde durur ve bulunamaz; oradaNABIZ_RELEASEkullanın. - Hiçbiri yoksa etiket gönderilmez.
Kural Node ve Laravel paketleriyle aynı. Gunicorn'un çalışma dizini uygulama kökü
değilse (--chdir yoksa) 4. adım bir şey bulamaz; nabiz-durum aynı dizinden
çalıştırılınca bunu kaynak: yok olarak gösterir.
| Tür | Ne zaman |
|---|---|
exception |
Yakalanmamış istisna, report() çağrısı |
fatal |
MemoryError, RecursionError, SystemError — yorumlayıcının sınırına çarpmak |
http_5xx |
Yanıt kodu ≥ 500 |
slow_request |
Süre ≥ NABIZ_SLOW_REQUEST_MS |
Başarılı ve hızlı istekler raporlanmaz: her isteği göndermek izlenen uygulamaya da hub'a da yük olurdu.
- Hata yutulmaz. Handler zinciri korunur,
raiseengellenmez. - Süreç yönetimine karışılmaz.
sys.exitçağrılmaz, mevcutexcepthookzincirlenir. - Kendi hatasını raporlamaz. Tüm SDK kodu
try/exceptile sarılır. - Kullanıcı isteğini bekletmez. Gönderim arka plan thread'inden, kısa zaman aşımıyla.
- Hub erişilemezse sessizce vazgeçilir.
NABIZ_ENABLED=falseiken hiçbir veri gönderilmez.
Sürüm sabitlenmez: kurulan her zaman deponun son hâlidir. Karşılığında bir kural zorunlu hâle gelir — her yayında sürüm numarası yükseltilmelidir.
Sebep ölçüldü: pip, doğrudan git URL'i verilen bir paketi depoyu klonlayıp metadata'sını
okuduktan sonra sürüm numarasına bakar. Numara kuruluyla aynıysa kurulumu atlar ve
-U bunu değiştirmez:
| Komut | Sürüm aynıysa | Sürüm yükselmişse |
|---|---|---|
pip install -r requirements.txt |
atlar | kurar |
pip install -U ... |
atlar | kurar |
pip install --force-reinstall ... |
kurar | kurar |
Yani numara yükseltilmeden yapılan bir yayın, kurulu projelere hiç ulaşmaz ve bu sessizce olur — paketin bütün tasarımının karşı durduğu arıza biçimi.
Sürüm çıkarma sırası:
pyproject.tomliçindekiversionvesrc/nabiz/reporter.pyiçindekiSDK_VERSIONbirlikte yükseltilir. İkisi ayrışırsa panelde yanlış SDK sürümü görünür.CHANGELOG.md'ye giriş.python -m unittest discover -s tests- Commit,
git tag vX.Y.Z,git push origin vX.Y.Z. - Kurulu projelerde
pip install -r requirements.txt, ardındannabiz-durumile doğrulama. Panelde SDK sürümünün yenilendiği görülmelidir.
Acil bir düzeltme sürüm numarası yükseltmeden dağıtılacaksa tek yol
--force-reinstall; ama o durumda panel eski sürüm numarasını göstermeye devam eder ve
hangi sunucunun güncellendiği izlenemez.
# Çerçeve testleri için — yoksa 53 test sessizce atlanır
pip install "Flask==3.0.0" Django fastapi starlette httpx
python -m unittest discover -s testsÇıktıda skipped= görünüyorsa bir çerçeve kurulu değildir ve o entegrasyon
sınanmamıştır (Flask 17, Django 12, FastAPI/Starlette 24 test).
0.1.0'daki çift kayıt ve kaybolan hata tam bu yüzden fark edilmedi.
Testler hub'ın imza doğrulamasını (VerifyProjectSignature) ve gövde sınırlarını
birebir uygulayan sahte bir hub'a karşı koşar: imzanın gerçekten kabul edilip
edilmediği burada görülür, "204 aldım" demek yeterli değildir.