PASOE: Server-Side Profiling

Dwa lata temu napisałem trzeci post z serii o narzędziu Profiler – narzędziu deweloperskim wykorzystanym w lokalnych sesji klienckich.
Tym razem napiszę o trudniejszym użyciu tej techniki dla sesji serwera PASOE. Dane profilowania można zbierać zarówno dla modelu production jak i development.

Zbieranie danych z PASOE różni się w porównaniu z lokalną sesją. Pierwszym krokiem jest utworzenie specjalnego magazynu diagnostycznego, do którego będa trafiały dane z jednego lub kilku agentów wielosesyjnych

OpenEdge udostępnia w tym celu aplikację o nazwie oediagstore.war, którą można wdrożyć na instancji PASOE. Ponieważ ilość magazynowanej informacji będzie dla nas prawdopodobnie zbyt duża będziemy mogli ją przefiltrować. Filtry są konfigurowane i włączane za pomocą interfejsów JMX i REST API.
Ostatnim krokiem będzie użycie Profiler Viewer w Developer Studio, aby wyświetlić profilowane dane, jak opisałem to już kiedyś dla lokalnych danych.

Pierwszym krokiem jest utworzenie instancji serwera PASOE demoDiagnosticStore, która będzie zarządzać bazą danych (nie jest to instancja która zarządza naszą aplikacją!):
pasman create -v -p 8850 -P 8851 -s 8852 -f demoDiagnosticStore
i wdrażamy aplikację zarządzająca magazynem danych, która znajduje się w katalogu %DLC%\servers\pasoe\extras\oediagstore.war:
pasman deploy -I demoDiagnosticStore %DLC%\servers\pasoe\extras\oediagstore.war
Teraz w podkatalogu instancji work tworzymy pustą bazę danych oediagdb (jeśli chcemy utworzyć bazę o innej nazwie musimy zmienić to w ustawieniach AppServer.SessMgr w pliku conf/openedge.properties).


Możemy sprawdzić w OE Management czy baza ta będzie uruchamiana przez agentów PASOE:

Teraz uruchamiamy serwer bazy:
proserve oediagdb -S 5555
i uruchamiamy sesję kliencką:
prowin -db oediagdb
W oknie procedur wpisujemy prosty kod do załadowania schematu bazy:

RUN prodict/load_df.p (INPUT "oediagstore.df").
QUIT.

Można zamknąć okno edytora i zrestartować PASOE aby połączył się z bazą.
pasman pasoestart -I demoDiagnosticStore -timeout 200

Do przetestowania profilowania potrzebujemy jeszcze naszą instancję roboczą, tutaj jest to instancja o nazwie profileTargetInstance. Musi mieć ona wdrożoną aplikację oemanager.war.

Będziemy teraz tworzyć (w edytorze tekstowym) i uruchamiać zapytania JMX. Należy dokładnie zwracać uwagę na składnię tych zapytań.
Pierwsze zwraca ID uruchomionych agentów dla tej instancji.

{"O":"PASOE:type=OEManager,name=AgentManager","M":["getAgents","profileTargetInstance"]}

Zapytanie zapisujemy jako agentInfo.qry w podkatalogu /bin dla instancjini i uruchamiamy z wiersza poleceń.
oejmx.bat -R -Q agentInfo.qry
Wynik działania znajduje się w pliku tekstowym wygenerowanym do podkatalogu /temp.

{"getAgents":{"agents":[{"agentId":"nKD8vEGLSju-p2mgwQXrdw","pid":"27564","state":"AVAILABLE"}]}}

Dla nas ważny jest agentID, ktory posłuży do napisania drugiego zapytania, którego zadaniem jest włączenie przechwytywania danych diagnostycznych dla następnych 100 żądań o status serwera. Używa również filtrów AdapterMask i Proclist (u nas są puste).
Uwaga: w zapytaniach JMX nie może być znaków łamania wiersza. Tutaj są tylko dla lepszej czytelności.

{"O":"PASOE:type=OEManager,name=AgentManager",
"M":["pushProfilerData","nKD8vEGLSju-p2mgwQXrdw",
"http://localhost:8850/oediagstore/web/diag",100,
"{\"Coverage\":true,\"AdapterMask\":null,
\"ProcList\":null,\"TestRunDescriptor\":\"Sample Test\"}"]}

Plik zapisujemy jako diagInfo.qry i uruchamiamy:
oejmx.bat -R -Q diagInfo.qry
Efekt widać ponownie w pliku tekstowym w podkatalogu /temp.

{"pushProfilerData":
{"ABLReturnVal":true,
"agentId":"nKD8vEGLSju-p2mgwQXrdw",
"pid":"27564"}}

Jeśli ABLReturnVal wynosi true to znaczy, że uruchomienie zapytania zakończyło się sukcesem.
Piszemy trzecie zapytanie żeby dostać ustawienia profilera i zapisujemy je w pliku profilersettings.qry.

{"O":"PASOE:type=OEManager,name=AgentManager",
"M":["getProfilerSettings","nKD8vEGLSju-p2mgwQXrdw"]}

Uruchamiamy query oejmx.bat -R -Q profilersettings.qry
i otrzymujemy następujący wynik, czyli zestaw ustawień.

{"getProfilerSettings":{"ABLOutput":{"AdapterMask":"APSV,SOAP,REST,WEB",
"ProcList":"",
"RequestHiBound":-1,
"TestRunDescriptor":"Sample Test",
"bufsize":128,
"RequestLoBound":0,
"Coverage":true,
"RequestCount":100,
"Statistics":false,
"URL":"http://localhost:8850/oediagstore/web/diag"},
"ABLReturnVal":true,
"agentId":"nKD8vEGLSju-p2mgwQXrdw",
"pid":"27564"}}

Żeby wymusić jakiś prosty test i wygenerować dane do magazynu diagnostycznego wystarczy zwykła komenda ping:
curl http://host:port/rest/_oepingService/_oeping

Teraz w podkatalogu /work dla instancji demoDiagnosticStore uruchamiamy edytor podłączony do bazy oediag.db:
prowin -db oediag.db i piszemy kod ABL który ma pobrać dane z bazy i utworzyć plik dla profilera  o rozszerzeniu .prof.

DEFINE VAR requestId as Integer NO-UNDO.
DEFINE VAR fileName as Character NO-UNDO.
FOR EACH ProfiledRequest:    
	requestId = requestId + 1.    
	fileName =  "C:/OpenEdge/WRK/profiler_" + STRING(requestId) + ".prof".
    COPY-LOB ProfiledRequest.PerfData TO FILE fileName.
    MESSAGE fileName VIEW-AS ALERT-BOX.
END.

Plik .prof otwieramy w Developers Studio i widzimy znajomy widok.

Jak widać technika ta jest dość żmudna, ale w końcu otrzymujemy dane do analizy.