Wzorce logowania
Twoje API zwraca losowe błędy 500 na produkcji. „Logi” to nieustrukturyzowane ciągi z console.log, nie potrafisz prześledzić pojedynczego żądania przez trzy usługi, a twój inżynier dyżurny grepuje czysty tekst o 3 nad ranem. Rozwiązaniem nie jest pisanie frameworka do logowania ręcznie — chodzi o to, by twoje narzędzie AI zamieniło to, co już masz, w strukturalne, skorelowane i zredagowane logi w jednym przebiegu.
Ten przepis pokazuje prompty i pętlę przeglądu. Ręcznie pisana klasa loggera to coś, co AI usuwa, a nie coś, co wdrażasz.
Co z tego wyniesiesz
Dział zatytułowany „Co z tego wyniesiesz”- Prompt, który zamienia każdy
console.logw repozytorium na strukturalne logowaniewinston(lubpino) z formatterem JSON,defaultMetai warstwą redakcji - Prompt, który dodaje middleware korelujące żądania, dzięki czemu jedno
requestIdpodąża za żądaniem przez każde wywołanie downstream za pomocąAsyncLocalStorage - Prompt, który audytuje twoją bazę kodu pod kątem instrukcji logujących sekrety i dane osobowe, zanim trafią na dysk
- Tryby awarii, które sprawiają, że logowanie wygenerowane przez AI wygląda dobrze podczas przeglądu, a psuje się na produkcji
Przebieg pracy
Dział zatytułowany „Przebieg pracy”Błędem jest proszenie AI o „dodanie logowania”. Dostajesz porozrzucane wywołania logger.info bez żadnego schematu. Zamiast tego przeprowadź trzy oddzielne przebiegi: wybierz bibliotekę, uczyń logi strukturalnymi i zredagowanymi, a potem skoreluj je. Oceń diff po każdym przebiegu.
Krok 1: Wybierz utrzymywaną bibliotekę, a nie autorską klasę
Dział zatytułowany „Krok 1: Wybierz utrzymywaną bibliotekę, a nie autorską klasę”Nie pozwól, by AI samodzielnie sklecił SamplingLogger czy MultiTransportLogger. Zarówno winston, jak i pino już rozwiązują kwestie transportów, poziomów, formatowania i redakcji — i są utrzymywane. pino to szybszy domyślny wybór (serializuje poza gorącą ścieżką); winston jest bardziej elastyczny, jeśli potrzebujesz wielu transportów. Wskaż ten wybór w swoim prompcie, żeby AI nie wymyślało koła na nowo.
Krok 2: Zamień console.log na strukturalne, zredagowane logowanie
Dział zatytułowany „Krok 2: Zamień console.log na strukturalne, zredagowane logowanie”To mechaniczny refaktor wielu plików — dokładnie to, w czym dobry jest tryb agentowy i przebiegi headless. Prompt jest w zasadzie identyczny dla wszystkich trzech narzędzi; różni się tylko sposób uruchomienia.
Otwórz tryb agentowy (Cmd/Ctrl+I), wskaż mu src/ i wklej poniższy prompt do strukturalnego logowania. Cursor edytuje każde miejsce wywołania w plikach w jednym przebiegu; przejrzyj każdą zmianę w widoku diff i użyj punktu kontrolnego przed akceptacją, abyś mógł wycofać cały refaktor, jeśli schemat jest błędny. Trzymaj otwarty src/lib/logger.ts jako plik kotwiczący, aby agent scentralizował konfigurację tam, zamiast definiować logger osobno w każdym module.
Uruchom go w trybie headless, by zmiana była skryptowalna i testowalna za jednym razem:
claude -p "Refactor every console.log/console.error in src/ to the winston logger in src/lib/logger.ts. After editing, run: npm test" \ --allowedTools "Read" "Edit" "Bash(npm test:*)"-p uruchamia w trybie nieinteraktywnym; --allowedTools pozwala mu edytować i uruchamiać zestaw testów bez pytania przy każdym pliku, więc refaktor i jego weryfikacja dzieją się razem.
W Codex CLI uruchom prompt jako argument pozycyjny i pozwól mu nanieść zmiany, bramkując polecenia powłoki w razie niepowodzenia:
codex --ask-for-approval on-failure \ "Replace all console.* calls in src/ with the structured winston logger in src/lib/logger.ts, then run npm test"W przypadku dużego repozytorium wyślij ten sam prompt do Codex Cloud z rozszerzenia IDE lub aplikacji webowej i przejrzyj powstały diff jako PR, zamiast obserwować go lokalnie.
Oto sam prompt. Jest celowo stanowczy — niejasny prompt „dodaj logowanie” to właśnie to, co stworzyło ten nieprzeszukiwalny bałagan, od którego zaczynałeś.
Gdy diff zostanie naniesiony, oceń go pod kątem trzech pytań, zanim go zaakceptujesz:
- Czy komunikat to stała, przeszukiwalna wartość?
logger.info('User login')da się zgrepować;logger.info(`User ${id} logged in`)— nie. Odrzucaj interpolowane komunikaty — części dynamiczne należą do obiektu metadanych. - Czy redakcja trafiła do wspólnego formattera, a nie do instrukcji
deleteprzy każdym wywołaniu? Jeśli AI rozsiało ręczne liniedelete obj.password, odeślij je z powrotem: redakcja musi być formatem stosowanym do każdego logu, inaczej zostanie zapomniana przy kolejnej linii logu, którą ktoś doda. - Czy poziomy mają sens? Obsłużony błąd walidacji to
warn, nieobsłużone 500 toerror. Jeśli wszystko stało sięinfo, twoje alertowanie jest teraz bezużyteczne.
Krok 3: Dodaj korelację żądań, która przetrwa granice asynchroniczne
Dział zatytułowany „Krok 3: Dodaj korelację żądań, która przetrwa granice asynchroniczne”requestId, które istnieje wyłącznie na req, jest bezwartościowe w momencie, gdy wywołujesz funkcję usługi, która nie przyjmuje req. Solidnym wzorcem jest AsyncLocalStorage: zapisz kontekst żądania raz w middleware, a potem dowolny logger w dowolnym miejscu stosu wywołań odczyta go bez przeciągania req przez każdą sygnaturę. Zmuś AI, by użyło go jawnie — zostawione samo sobie będzie przekazywać req.logger dookoła i zgubi identyfikator przy pierwszym setTimeout lub odłączonym promisie.
Klauzula „udowodnij to” ma znaczenie: zmusza AI do zademonstrowania propagacji przez granicę asynchroniczną, zamiast twierdzenia, że to działa. Jeśli nie potrafi pokazać identyfikatora pojawiającego się w funkcji, która nigdy nie otrzymała req, to implementacja jest tym kruchym wariantem.
Krok 4: Audytuj pod kątem wycieku sekretów i danych osobowych
Dział zatytułowany „Krok 4: Audytuj pod kątem wycieku sekretów i danych osobowych”Redakcja po nazwie klucza jest konieczna, ale niewystarczająca — adresy e-mail i IP to dane osobowe w rozumieniu RODO i nie wyłapie ich matcher na password/token. Jako ostatni krok przeprowadź dedykowany przebieg audytowy.
Kiedy to się psuje
Dział zatytułowany „Kiedy to się psuje”Oto tryby awarii, które przechodzą przegląd kodu i wychodzą na jaw o 3 nad ranem.
- AI loguje pełne ciała żądań „do debugowania”. Pojedyncze
logger.info('request', { body: req.body })zrzuci hasła, tokeny i numery kart do twojego magazynu logów, gdy tylko ktoś trafi na trasę rejestracji. Redakcja po kluczu cię nie uratuje, jeśli całe ciało jest zagnieżdżone pod jednym niewinnie wyglądającym kluczem. Zabroń logowania surowych ciał w prompcie i zweryfikuj, że tabela audytu z Kroku 4 jest pusta, zanim wdrożysz. - Kontekst
logger.child()jest tracony przez granice asynchroniczne. Logger potomny powiązany w middleware nie podąża automatycznie dosetTimeout, odłączonego.then()ani workera kolejki. To dokładnie dlatego Krok 3 używaAsyncLocalStoragezamiastreq.logger— jeśli widzisz identyfikator korelacji obecny w logu żądania, ale brakujący w logu usługi downstream, to trafiłeś na ten problem, a rozwiązaniem jest odczyt kontekstu z magazynu, a nie z przekazanego loggera potomnego. - Wszystko stało się
info, więc alertowanie to szum. Jeśli refaktor spłaszczył wszystkie poziomy, twój alert „loguj przy błędach” albo nigdy się nie odpala, albo odpala przy każdym żądaniu. Uruchom ponownie pytanie o przegląd poziomów z Kroku 2 i każ AI przeklasyfikować:warndla obsłużonych/4xx,errordla nieobsłużonych/5xx,debugdla diagnostyki o wysokiej częstotliwości. - Synchroniczne logowanie na gorącej ścieżce dodaje opóźnienia. Zapis do wolnego transportu (plik na zasobie sieciowym, zdalny odbiornik HTTP) w linii z żądaniem blokuje je. Użyj
pino(asynchronicznego z założenia) lub buforowanego/asynchronicznego transportu dlawinstoni nigdy nie róbawaitna zapisie logu w handlerze żądania. - MCP utrzymywanej biblioteki odpowiedziałoby za ciebie na pytanie o konfigurację. Jeśli AI zgaduje API
winstonlubpinoi myli się w subtelny sposób, podłącz Context7 MCP (@upstash/context7-mcp) i dodaj do promptu „use Context7 for the winston/pino docs” — wciąga aktualną dokumentację biblioteki do kontekstu, dzięki czemu wygenerowana konfiguracja pasuje do zainstalowanej wersji, a nie do zmyślonej.
Co dalej
Dział zatytułowany „Co dalej”- Wzorce debugowania — zamień te strukturalne logi w szybki przepływ analizy przyczyn źródłowych
- Wzorce monitorowania — alertuj na sygnały, które teraz emitują twoje logi
- Wzorce odzyskiwania — łagodna degradacja, gdy błędy, które logujesz, naprawdę się odpalą