Pokazuje ślad stosu z działającej aplikacji Python


340

Mam tę aplikację Python, która od czasu do czasu zacina się i nie mogę się dowiedzieć, gdzie.

Czy jest jakiś sposób, aby zasygnalizować interpreterowi języka Python, aby pokazał dokładnie działający kod?

Jakiś rodzaj śledzenia stosu w locie?

Powiązane pytania:



Odpowiedzi:


315

Mam moduł, którego używam do takich sytuacji - gdzie proces będzie działał przez długi czas, ale czasami utknie z nieznanych i nieodwracalnych powodów. Jest nieco zhackowany i działa tylko na Uniksie (wymaga sygnałów):

import code, traceback, signal

def debug(sig, frame):
    """Interrupt running process, and provide a python prompt for
    interactive debugging."""
    d={'_frame':frame}         # Allow access to frame object.
    d.update(frame.f_globals)  # Unless shadowed by global
    d.update(frame.f_locals)

    i = code.InteractiveConsole(d)
    message  = "Signal received : entering python shell.\nTraceback:\n"
    message += ''.join(traceback.format_stack(frame))
    i.interact(message)

def listen():
    signal.signal(signal.SIGUSR1, debug)  # Register handler

Aby użyć, po prostu wywołaj funkcję Listen () w pewnym momencie, gdy program się uruchamia (możesz nawet umieścić go w site.py, aby wszystkie programy python go używały) i pozwolić mu działać. W dowolnym momencie wyślij procesowi sygnał SIGUSR1, używając kill lub w pythonie:

    os.kill(pid, signal.SIGUSR1)

Spowoduje to, że program przejdzie do konsoli Pythona w punkcie, w którym się aktualnie znajduje, pokazując ślad stosu i umożliwiając manipulowanie zmiennymi. Użyj control-d (EOF), aby kontynuować działanie (choć zauważ, że prawdopodobnie przerwiesz każde wejście / wyjście itp. W miejscu, w którym zasygnalizujesz, więc nie jest to w pełni nieinwazyjne.

Mam inny skrypt, który robi to samo, tyle że komunikuje się z uruchomionym procesem za pomocą potoku (aby umożliwić debugowanie procesów w tle itp.). Jest tu trochę za dużo, ale dodałem go jako przepis na książkę kucharską w języku Python .


1
Dzięki! Właśnie tego szukałem. Może mógłbyś również opublikować ten skrypt z obsługą potoku na stronie z fragmentami w języku Python?
— Seb

2
Teraz opublikowałem go na stronie książki kucharskiej Pythona - dodano link.
— Brian

1
Musiałem dodać „import readline”, aby włączyć funkcje historii.
— miracle2k

2
Świetna wskazówka! Działa to również w celu wysłania sygnału do wszystkich procesów zawierających słowo „mypythonapp”: pkill -SIGUSR1 -f mypythonapp
— Alexander

10
Jeśli aplikacja jest zablokowana, pętla interpretera języka Python może nie być w stanie uruchomić się w celu przetworzenia sygnału. Użyj faulthandlermodułu (i jego backportu znalezionego w PyPI) do obsługi sygnału poziomu C, która wydrukuje stos Pythona bez konieczności reagowania na pętlę interpretera.
— gps

146

Sugestia zainstalowania modułu obsługi sygnałów jest dobra i bardzo go używam. Na przykład, bzr domyślnie instaluje moduł obsługi SIGQUIT , który wywołuje pdb.set_trace()natychmiastowe upuszczenie do monitu pdb . (Zobacz bzrlib.breakin Dokładne szczegóły znajdują się modułu .) Dzięki pdb możesz nie tylko uzyskać bieżący ślad stosu, ale także sprawdzić zmienne itp.

Czasami jednak muszę debugować proces, w którym nie miałem zdolności przewidywania, aby zainstalować moduł obsługi sygnału. W systemie Linux możesz dołączyć proces gdb do procesu i uzyskać ślad stosu Pythona za pomocą niektórych makr gdb. Umieścić http://svn.python.org/projects/python/trunk/Misc/gdbinit w ~/.gdbinit, a następnie:

  • Dołącz gdb: gdb -p PID
  • Uzyskaj śledzenie stosu python: pystack

Niestety nie jest całkowicie niezawodny, ale działa przez większość czasu.

Wreszcie, dołączanie straceczęsto daje dobry obraz tego, co robi proces.


2
Znakomity! Polecenie pystack czasami się blokuje, ale zanim to zrobi, daje mi kompletny ślad procesu w liniach kodu Pythona, bez potrzeby przygotowania.
— muudscope

26
Drobna aktualizacja: ta technika gdb (i zaktualizowany kod) jest udokumentowana na wiki.python.org/moin/DebuggingWithGdb Na tym froncie wprowadzono pewne zmiany, udokumentowane pod tym adresem URL i najwyraźniej gdb 7 ma pewne wsparcie dla Pythona.
— Nelson

7
O ile wiem, to działa naprawdę tylko wtedy, gdy masz symbole debugowania wkompilowane w twój plik binarny Pythona - np .: uruchomiłeś program z python2-dbg (na Ubuntu, jest to osobny pakiet python-dbg). Bez tych symboli nie wydaje się, aby uzyskać wiele użytecznych informacji.
— drevicko

1
w moim przypadku ten powrót Unable to locate python framedo każdego polecenia
— seriyPS

6
gdb 7+ - z obsługą Pythona zapewnia python-gdb.py. Więcej informacji tutaj: chezsoi.org/lucas/blog/2014/11/07/en-gdb-python-macros
— Lucas Cimon

71

Prawie zawsze mam do czynienia z wieloma wątkami, a główny wątek na ogół niewiele robi, więc najciekawsze jest zrzucenie wszystkich stosów (co bardziej przypomina zrzut Java). Oto implementacja oparta na tym blogu :

import threading, sys, traceback

def dumpstacks(signal, frame):
    id2name = dict([(th.ident, th.name) for th in threading.enumerate()])
    code = []
    for threadId, stack in sys._current_frames().items():
        code.append("\n# Thread: %s(%d)" % (id2name.get(threadId,""), threadId))
        for filename, lineno, name, line in traceback.extract_stack(stack):
            code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
            if line:
                code.append("  %s" % (line.strip()))
    print "\n".join(code)

import signal
signal.signal(signal.SIGQUIT, dumpstacks)

53

Uzyskiwanie śladu stosu nieprzygotowanego programu python, działającego w podstawowym pythonie bez symboli debugowania, można wykonać za pomocą pirazytu . Działa jak urok dla mnie w Ubuntu Trusty:

$ sudo pip install pyrasite
$ echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
$ sudo pyrasite 16262 dump_stacks.py # dumps stacks to stdout/stderr of the python program

(Hat tip do @Albert, którego odpowiedź zawierała między innymi wskaźnik do tego).


5
Działa to świetnie dla mnie, gdzie dump_stacks.pybył po prostuimport traceback; traceback.print_stack()
— John Lehmann

2
traceback -lzawiera listę predefiniowanych skryptów Pythona, których możesz użyć, i dump_stacks.pyjest jednym z nich. Jeśli używasz własnego (na przykład do zapisywania śladu stosu w pliku), rozsądnie może być użycie innej nazwy.
— johndodo,

12
Ważna wskazówka: uruchom apt-get install gdb python-dbg(lub odpowiednik) przed uruchomieniem pirazytu, w przeciwnym razie po cichu zawiedzie. W przeciwnym razie działa jak urok!
— johndodo,

Ostatnie wydanie pirazytu miało miejsce w 2012 roku
— Boris

35
>>> import traceback
>>> def x():
>>>    print traceback.extract_stack()

>>> x()
[('<stdin>', 1, '<module>', None), ('<stdin>', 2, 'x', None)]

Możesz również ładnie sformatować ślad stosu, zobacz dokumenty .

Edycja : Aby zasymulować zachowanie Javy, zgodnie z sugestią @Douglas Leeder, dodaj:

import signal
import traceback

signal.signal(signal.SIGUSR1, lambda sig, stack: traceback.print_stack(stack))

do kodu startowego w aplikacji. Następnie możesz wydrukować stos, wysyłając SIGUSR1go do działającego procesu Python.


2
Spowoduje to wydrukowanie tylko śladu głównego wątku. Muszę jeszcze znaleźć rozwiązanie, aby zobaczyć ślady dla wszystkich wątków. W rzeczywistości w Pythonie brakuje interfejsu API do pobierania stosu z obiektu Thread, chociaż threading.enumerate () daje dostęp do wszystkich obiektów Thread.
— haridsv

Działa to świetnie na cygwin. Drukuje tylko trzy linie śladu stosu, ale to wystarczy, aby uzyskać wskazówkę
— slashdottir

28

Traceback Moduł posiada kilka ciekawych funkcji, wśród nich: print_stack:

import traceback

traceback.print_stack()

1
Aby zapisać ślad stosu do pliku, użyj: import traceback; f = open('/tmp/stack-trace.log', 'w') traceback.print_stack(file=f) f.close()
— GuruM

1
+1 do @gulgi za jego łatwą w użyciu odpowiedź. Niektóre inne odpowiedzi wyglądały na bardzo skomplikowane w przypadku mojego prostego zadania polegającego na uzyskaniu śladu stosu wywołań z funkcji skryptu.
— GuruM,

24

Możesz wypróbować moduł obsługi błędów . Zainstaluj go za pomocą pip install faulthandleri dodaj:

import faulthandler, signal
faulthandler.register(signal.SIGUSR1)

na początku twojego programu. Następnie wyślij SIGUSR1 do swojego procesu (np .:), aby kill -USR1 42wyświetlić śledzenie wszystkich wątków Pythona na standardowym wyjściu. Przeczytaj dokumentację, aby uzyskać więcej opcji (np .: zaloguj się do pliku) i inne sposoby wyświetlania śledzenia.

Moduł jest teraz częścią Python 3.3. W przypadku Python 2 zobacz http://faulthandler.readthedocs.org/


20

To, co naprawdę mi pomogło, to wskazówka spiv (którą głosowałbym i komentowałbym, gdybym miał punkty reputacji), aby uzyskać ślad stosu z nieprzygotowanego procesu Pythona. Tyle że nie działało, dopóki nie zmodyfikowałem skryptu gdbinit . Więc:

  • pobierz http://svn.python.org/projects/python/trunk/Misc/gdbinit i włóż~/.gdbinit

  • edytuj, zmieniając PyEval_EvalFramenaPyEval_EvalFrameEx[edycja: nie jest już potrzebne; plik połączony ma już tę zmianę na dzień 14.01.2010]

  • Dołącz gdb: gdb -p PID

  • Uzyskaj śledzenie stosu python: pystack


Wydaje się, że gdbinit pod wspomnianym adresem URL ma łatkę, którą sugerujesz. W moim przypadku, gdy pisałem pystack, mój procesor właśnie się zawiesił. Nie pewny dlaczego.
— Jesse Glick

2
Nie, nie ma - przepraszam, nie było jasne, ponieważ ta linia pojawia się w trzech miejscach. Łatka, którą powiązałem z, pokazuje, którą zmieniłem, kiedy zobaczyłem tę pracę.
— Gunnlaugur Briem

2
Podobnie jak odpowiedź @ spiv, wymaga to, aby program działał pod Pythonem skompilowanym z symbolami debugowania. W przeciwnym razie dostanieszNo symbol "co" in current context.
— Nickolay

12

Dodałbym to jako komentarz do odpowiedzi haridsv , ale brakuje mi reputacji, aby to zrobić:

Niektórzy z nas nadal tkwią w wersji Pythona starszej niż 2.6 (wymagana dla Thread.ident), więc dostałem kod działający w Pythonie 2.5 (choć bez wyświetlania nazwy wątku) jako taki:

import traceback
import sys
def dumpstacks(signal, frame):
    code = []
    for threadId, stack in sys._current_frames().items():
            code.append("\n# Thread: %d" % (threadId))
        for filename, lineno, name, line in traceback.extract_stack(stack):
            code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
            if line:
                code.append("  %s" % (line.strip()))
    print "\n".join(code)

import signal
signal.signal(signal.SIGQUIT, dumpstacks)

11

python -dv twójscript.py

To sprawi, że interpreter będzie działał w trybie debugowania i da ci ślad tego, co robi interpreter.

Jeśli chcesz interaktywnie debugować kod, powinieneś go uruchomić w następujący sposób:

python -m pdb yourscript.py

Mówi to interpreterowi Pythona o uruchomieniu skryptu z modułem „pdb”, który jest debuggerem Pythona, jeśli uruchomisz go w ten sposób, interpreter zostanie uruchomiony w trybie interaktywnym, podobnie jak GDB


To nie odpowiada na pytanie. Pytanie dotyczyło już uruchomionego procesu.
— dbn

11

Spójrz na faulthandlermoduł, nowy w Pythonie 3.3. faulthandlerBackport do użytku w Pythonie 2 jest dostępny na PyPI.


2
Nowsza odpowiedź @haypo omawia to bardziej szczegółowo. Nie jestem pewien, jak zwykle jest to obsługiwane w przypadku SO, ale źle jest mieć dwie zasadniczo zduplikowane odpowiedzi ...
— Nickolay

7

W systemie Solaris można używać pstack (1). Nie są wymagane żadne zmiany w kodzie Pythona. na przykład.

# pstack 16000 | grep : | head
16000: /usr/bin/python2.6 /usr/lib/pkg.depotd --cfg svc:/application/pkg/serv
[ /usr/lib/python2.6/vendor-packages/cherrypy/process/wspbus.py:282 (_wait) ]
[ /usr/lib/python2.6/vendor-packages/cherrypy/process/wspbus.py:295 (wait) ]
[ /usr/lib/python2.6/vendor-packages/cherrypy/process/wspbus.py:242 (block) ]
[ /usr/lib/python2.6/vendor-packages/cherrypy/_init_.py:249 (quickstart) ]
[ /usr/lib/pkg.depotd:890 (<module>) ]
[ /usr/lib/python2.6/threading.py:256 (wait) ]
[ /usr/lib/python2.6/Queue.py:177 (get) ]
[ /usr/lib/python2.6/vendor-packages/pkg/server/depot.py:2142 (run) ]
[ /usr/lib/python2.6/threading.py:477 (run)
etc.

2
Wydaje się, że istnieje program Debian / Ubuntu, pstackktóry robi to samo
— Rory

1
Wydaje się, że daje jedynie ślad wstecz w Linuksie, a nie ślad zwrotny Pythona z nazwą pliku i numerami linii.
— ogrisel

6

Jeśli korzystasz z systemu Linux, skorzystaj z niesamowitości gdbdzięki rozszerzeniom debugowania Pythona (może być w python-dbglub w python-debuginfopakiecie). Pomaga również w aplikacjach wielowątkowych, aplikacjach GUI i modułach C.

Uruchom swój program z:

$ gdb -ex r --args python <programname>.py [arguments]

To instruuje, jak gdbgo przygotować python <programname>.py <arguments>i rusunąć.

Teraz, kiedy program zawiesi się, przełącz się na gdbkonsolę, naciśnij Ctr+Ci wykonaj:

(gdb) thread apply all py-list

Zobacz przykładową sesję i więcej informacji tutaj i tutaj .


6

Przez jakiś czas szukałem rozwiązania do debugowania moich wątków i znalazłem je tutaj dzięki haridsv. Używam nieco uproszczonej wersji wykorzystującej traceback.print_stack ():

import sys, traceback, signal
import threading
import os

def dumpstacks(signal, frame):
  id2name = dict((th.ident, th.name) for th in threading.enumerate())
  for threadId, stack in sys._current_frames().items():
    print(id2name[threadId])
    traceback.print_stack(f=stack)

signal.signal(signal.SIGQUIT, dumpstacks)

os.killpg(os.getpgid(0), signal.SIGQUIT)

Na moje potrzeby filtruję wątki według nazwy.


3

Warto spojrzeć na Pydb , „rozszerzoną wersję debugera Pythona luźno opartą na zestawie poleceń gdb”. Obejmuje menedżerów sygnałów, którzy mogą zadbać o uruchomienie debuggera po wysłaniu określonego sygnału.

Projekt Summer of Code z 2006 r. Dotyczył dodania funkcji zdalnego debugowania do pydb w module o nazwie mpdb .


Wygląda na to, że przeszły dwa ( 1 ) przepisania ( 2 ) bez dodawania funkcji załączania przez PID, której szukałem ...
— Nickolay

3

Zhakowałem razem narzędzie, które dołącza się do działającego procesu Pythona i wstrzykuję trochę kodu, aby uzyskać powłokę Pythona.

Zobacz tutaj: https://github.com/albertz/pydbattach


1
Uwaga: nie jest oczywiste, jak to zbudować. Dzięki za linki, które umieściłeś w README: pyrasitedziałało idealnie!
— Nickolay

3

Można to zrobić za pomocą doskonałego py-spy . Jest to profiler do próbkowania dla programów w języku Python , więc jego zadaniem jest dołączanie do procesów w języku Python i próbkowanie stosów wywołań. Dlatego py-spy dump --pid $SOME_PIDwszystko, co musisz zrobić, aby zrzucić stosy wywołań wszystkich wątków w tym $SOME_PIDprocesie. Zazwyczaj potrzebuje eskalowanych uprawnień (do odczytu pamięci procesu docelowego).

Oto przykład tego, jak to wygląda w wątkowej aplikacji Python.

$ sudo py-spy dump --pid 31080
Process 31080: python3.7 -m chronologer -e production serve -u www-data -m
Python v3.7.1 (/usr/local/bin/python3.7)

Thread 0x7FEF5E410400 (active): "MainThread"
    _wait (cherrypy/process/wspbus.py:370)
    wait (cherrypy/process/wspbus.py:384)
    block (cherrypy/process/wspbus.py:321)
    start (cherrypy/daemon.py:72)
    serve (chronologer/cli.py:27)
    main (chronologer/cli.py:84)
    <module> (chronologer/__main__.py:5)
    _run_code (runpy.py:85)
    _run_module_as_main (runpy.py:193)
Thread 0x7FEF55636700 (active): "_TimeoutMonitor"
    run (cherrypy/process/plugins.py:518)
    _bootstrap_inner (threading.py:917)
    _bootstrap (threading.py:885)
Thread 0x7FEF54B35700 (active): "HTTPServer Thread-2"
    accept (socket.py:212)
    tick (cherrypy/wsgiserver/__init__.py:2075)
    start (cherrypy/wsgiserver/__init__.py:2021)
    _start_http_thread (cherrypy/process/servers.py:217)
    run (threading.py:865)
    _bootstrap_inner (threading.py:917)
    _bootstrap (threading.py:885)
...
Thread 0x7FEF2BFFF700 (idle): "CP Server Thread-10"
    wait (threading.py:296)
    get (queue.py:170)
    run (cherrypy/wsgiserver/__init__.py:1586)
    _bootstrap_inner (threading.py:917)
    _bootstrap (threading.py:885)  

2

pyringe to debugger, który może wchodzić w interakcje z uruchomionymi procesami Pythona, drukować ślady stosu, zmienne itp. bez konieczności wcześniejszej konfiguracji.

Chociaż w przeszłości często korzystałem z rozwiązania do obsługi sygnałów, w niektórych środowiskach wciąż może być trudno odtworzyć problem.


3
Najwyraźniej jest niekompatybilny z niektórymi kompilacjami gdb (np. Tą , którą zainstalowałem na ubuntu): github.com/google/pyringe/issues/16 , wymagając ręcznej przebudowy. Kolejny debugger pyrasitedziałał dla mnie jak urok.
— Nickolay,

1

Nie ma sposobu, aby podłączyć się do uruchomionego procesu Pythona i uzyskać rozsądne wyniki. To, co robię, jeśli procesy się blokują, to podłączanie się do sieci i próba ustalenia, co dokładnie się dzieje.

Niestety często strace jest obserwatorem, który „naprawia” warunki wyścigu, dzięki czemu dane wyjściowe są również bezużyteczne.


1
Tak, to prawda. Szkoda, że ​​pdb nie obsługuje dołączania się do uruchomionego procesu ...
— Bartosz Radaczyński

To nie jest prawda. Zobacz odpowiedź „spiv” powyżej, która pokazuje, jak podłączyć gdb i uzyskać ślad stosu Pythona.
— Andrew Cooke

To nie to samo - te makra gdb nie są niezawodne i nie zapewniają pełnego / znanego interfejsu pdb. Często żałuję, że ktoś nie napisał małej aplikacji, która użyłaby ptrace do wstrzyknięcia kodu bajtowego Pythona do działającego procesu Pythona i spowodowania, aby wykonał „import pdb; pdb.set_trace () ', może także po tymczasowym przekierowaniu sys.stdin / stdout.
— Marius Gedminas

To już nie jest prawda, zobacz inne odpowiedzi wskazujące na strzykawkę / pirasyt.
— Nickolay

1

W tym celu można użyć PuDB , debuggera w języku Python z interfejsem programu curses. Poprostu dodaj

from pudb import set_interrupt_handler; set_interrupt_handler()

do swojego kodu i użyj Ctrl-C, gdy chcesz się zepsuć. Możesz kontynuować ci przerwać ponownie wiele razy, jeśli go przegapisz i chcesz spróbować ponownie.


Kiedy używasz powyższej komendy w django, nie zapomnij poprawnie uruchomić serwera, aby zapobiec usterkom: „manage.py runserver --noreload --nothreading”
— potar

1

Jestem w obozie GDB z rozszerzeniami python. Postępuj zgodnie z https://wiki.python.org/moin/DebuggingWithGdb , co oznacza

  1. dnf install gdb python-debuginfo lub sudo apt-get install gdb python2.7-dbg
  2. gdb python <pid of running process>
  3. py-bt

Weź również pod uwagę info threadsi thread apply all py-bt.


Czy to normalne, aby uzyskać odpowiedź, jak Traceback (most recent call first): Python Exception <class 'gdb.error'> No frame is currently selected.: Error occurred in Python command: No frame is currently selected.podczas pracy py-btw gdb?
— crookedleaf

1
nieważne. to dlatego, że moja aplikacja działała jako sudo. gdb pyton <pid>Musiałem też uruchomić jako sudo.
— crookedleaf,

1

Jak debugować dowolną funkcję w konsoli :

Utwórz funkcję, w której używasz pdb.set_trace () , a następnie funkcję, którą chcesz debugować.

>>> import pdb
>>> import my_function

>>> def f():
...     pdb.set_trace()
...     my_function()
... 

Następnie wywołaj utworzoną funkcję:

>>> f()
> <stdin>(3)f()
(Pdb) s
--Call--
> <stdin>(1)my_function()
(Pdb) 

Miłego debugowania :)


0

Nie znam niczego podobnego do odpowiedzi Javy na SIGQUIT , więc może być konieczne wbudowanie go w aplikację. Może mógłbyś stworzyć serwer w innym wątku, który może uzyskać ślad stosu w odpowiedzi na wiadomość?


0

użyj modułu inspekcji.

import inspect help (inspect.stack) Pomoc na stosie funkcji w module inspect:

stos (kontekst = 1) Zwraca listę rekordów stosu ponad ramką dzwoniącego.

Uważam to za bardzo pomocne.


0

W Pythonie 3 pdb automatycznie zainstaluje moduł obsługi sygnałów przy pierwszym użyciu c (ont (inue)) w debuggerze. Naciśnięcie przycisku Control-C spowoduje powrót do tego miejsca. W Pythonie 2 znajduje się jedna linijka, która powinna działać nawet w stosunkowo starych wersjach (testowana w wersji 2.7, ale sprawdziłem źródła Pythona z powrotem do wersji 2.4 i wyglądało to dobrze):

import pdb, signal
signal.signal(signal.SIGINT, lambda sig, frame: pdb.Pdb().set_trace(frame))

pdb warto się nauczyć, jeśli poświęcasz trochę czasu na debugowanie Pythona. Interfejs jest nieco tępy, ale powinien być znany każdemu, kto używał podobnych narzędzi, takich jak gdb.


0

Jeśli musisz to zrobić z uWSGI, ma on wbudowany Python Tracebacker i wystarczy włączyć go w konfiguracji (numer jest dołączony do nazwy dla każdego pracownika):

py-tracebacker=/var/run/uwsgi/pytrace

Po wykonaniu tej czynności możesz wydrukować ślad, po prostu podłączając się do gniazda:

uwsgi --connect-and-read /var/run/uwsgi/pytrace1

0

W miejscu, w którym kod jest uruchamiany, możesz wstawić ten mały fragment kodu, aby zobaczyć ładnie sformatowany ślad wydruku stosu. Zakłada się, że masz folder o nazwie logsw katalogu głównym projektu.

# DEBUG: START DEBUG -->
import traceback

with open('logs/stack-trace.log', 'w') as file:
    traceback.print_stack(file=file)
# DEBUG: END DEBUG --!
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.