Miałem już zakończyć serię o serverless w gogle gdyż o cloud functions dużo więcej napisać się po prostu nie dało. Tak przynajmniej myślałem.  Mimo wszystko kontynuowałem czytanie na temat funkcji, co jest możliwe a co nie. Jakie są opcje i gdzie te funkcje mogą być wykorzystane. I gdyby nie ślepy traf to tego postu by nie było a moja opinia o funkcjach w googlach była by dość słaba – przynajmniej gorsza niż teraz jest.

Temat serveless Cię interesuje? Zapraszam na Kurs SERVERLESS - zapisz się być na bieżąco, otrzymać szczegóły kursu i dostać najlepszą ofertę!.

Przez zupełny przypadek trafiłem na opcję Debug w konsoli do zarządzania chmurą googla. Opcja ta umożliwia nam… tak jakby “debugowanie” funkcji, która działa na produkcji bez blokowania jej wykonania. “Debugowanie” a nie debugowanie, gdyż to wygląda jakby było zwykłym normalnym debugowanie a nie jest :) Po co coś takiego? No chociażby po to, że jak coś nam nie działa i nie wiemy co to zamiast co chwilę wgrywać nowszą wersję z odpowiednimi linijkami logowania danych i zagłębiania się w nich, możemy skorzystać z opcji “debugowania”. Bardzo przydatne dla edge case gdzie na wszystkich pozostałych środowiskach śmigało, ale akurat na produkcji coś idzie nie tak.

Jednak zaraz do tego dojdziemy co i jak. Przygotujmy sobie nasze środowisko i przy okazji poznamy trochę bliżej chmurę googla plus narzędzie gcloud.

Pre-wymagania

Trzeba zainstalować Cloud SDK.

Przygotowanie rozwiązania

Uwaga, może się okazać, że wam w ten sposób proces nie zadziała. Cały cloud jest raczej wersji beta w google. Więc jeżeli wam to nie działa, to należy podskoczyć do kroku Podłączenie do repozytorium na google i potem wrócić tutaj i wykonać all bez git init.

Stwórzmy sobie prosty katalog a w nim wykonajmy dwa bardzo ważne polecenia:

git init
npm init

Do gita dodajmy odpowiedni .gitignore – potrzebujemy przefiltrować po node.js jak i naszym edytorze, może być przydatny generator tego pliku – gitignore.io.

Mając wszystko gotowe, dodajmy plik .gitignore oraz packages.json to repozytorium.

Na razie możemy działać na lokalnym repo później, coś z nim zrobimy. Stwórzmy także plik index.js który będzie zawierał następujący kod:

exports.debugWorld = function (req, res) {
    let name = req.query.name || 'SomeName';

    if(true) {
        console.error('This IS ERROR!');
    }

    console.log('My custom awesome message to log!');

    res.status(200).send(`Hello, you can debug me ${name}!`);
}

Ponownie, dodajmy i commitujemy plik. Jesteśmy prawie gotowi!

Podłączenie do repozytorium na google cloud

By móc skorzystać z tej super fajnej funkcji potrzebujemy repozytorium do którego jest dostęp zewnątrz. To może być bitbucket albo github. Jednak by było zabawnie skorzystamy z opcji repozytoriów googla.

Otwieramy Source Repository i tworzymy nowe. Wystarczy podać nazwę i wtedy naszym oczom pokaże się ekran:

Dodanie remote - tutaj debugHello, ale to samo widziałem dla debugWorld ;)
Dodanie remote – tutaj debugHello, ale to samo widziałem dla debugWorld ;)

Możemy teraz wykonać podane kroki (najlepiej w katalogu naszego repozytorium). Należy też czytać informacje które się pojawią na konsoli – warningi itp. Gdyż tam są informacje typu: jak zostaniecie poproszeni o podanie hasła to kliknijcie anuluj.

Jeżeli się wam udało wykonać wszystkie kroki bez błędów to super!

Jeżeli jednak mieliście taki problem jak ja:

> git push --all google
fatal: unable to access 'https://source.developers.google.com/p/func-tests/r/debugWorld/': Unknown SSL protocol error in connection to source.developers.google.com:443

To rozwiązaniem problemu jest po prostu wykonanie drugiej opcji z podanych po utworzeniu repozytorium:

Jak z klonować repo (już z poprawną nazwą)
Jak z klonować repo (już z poprawną nazwą)

W tym wypadku jak zrobiłem push origin master to zadziałało to wszystko jak miodzio.

Pewny magiczny dodatek, który umożliwi nam debugowanie

Mając już wszystko podłączone, możemy zacząć przygotowywać nasze rozwiązanie pod debugger. By to zrobić, trzeba dodać paczkę @google-cloud/debug-agent do projektu:

npm install @google-cloud/debug-agent --save

A następnie w pliku index.js dodać:

require('@google-cloud/debug-agent').start({ allowExpressions: true });

Tak zmieniony plik packages.json jak i index.js pushujemy do origin master. Co to robi? Umożliwia nam to co zrobimy później.

PS.: ja korzystałem ze starej paczki @google/cloud-debug i też działało.

Ready, steady… jeszcze jeden krok

By móc debugować naszą funkcję musi ona zostać z deployowana. Jako, że przeszliśmy ścieżkę od repo to możemy dalej tak kontynuować. Czyli z wgrać naszą funkcję jako plik zip.

W tym celu wystarczy wykonać polecenie w naszym katalogu:

> gcloud beta functions deploy debugWorld --stage-bucket gutek-functions-src --trigger-http                           
Copying file://c:\users\gutek\appdata\local\temp\tmpwmszze\fun.zip [Content-Type=application/x-zip-compressed]...     
- [1 files][  598.0 B/  598.0 B]                                                                                      
Operation completed over 1 objects/598.0 B.                                                                           
Deploying function (may take a while - up to 2 minutes)...done.                                                       
availableMemoryMb: 256                                                                                                 
entryPoint: debugWorld                                                                                                
httpsTrigger:                                                                                                          
  url: https://us-central1-func-tests.cloudfunctions.net/debugWorld                                                    
latestOperation: operations/ZnVuYy10ZXN0cy91cy1jZW50cmFsMS9kZWJ1Z0hlbGxvL004TVUxdUdVZlBv                              
name: projects/func-tests/locations/us-central1/functions/debugWorld                                                  
serviceAccount: func-tests AT appspot.gserviceaccount.com                                                                
sourceArchiveUrl: gs://gutek-functions-src/us-central1-debugWorld-jifytvzyokfz.zip                                    
status: READY                                                                                                          
timeout: 60s                                                                                                          
updateTime: '2017-07-26T14:19:12Z'

To nam wgra funkcję (stworzy ją) i udostępni pod url:

https://us-central1-func-tests.cloudfunctions.net/debugWorld

Uwaga: --stage-bucket musi istnieć. Możecie go sobie stworzyć tutaj.

Jeżeli zaś o was mało interesuje i nie chcecie się bawić w taki deploy, to możemy stworzyć nową funkcję z poziomu UI i wskazać nasze istniejące repo jako źródło kodu. Dosłownie tylko tyle i aż tyle. Szkoda, że nie da się wybrać repo a trzeba to z palca robić. Ale działa.

Niezależnie jaki sposób deploymentu został użyty, funkcje trzeba przynajmniej raz odpalić by móc ją debugować.

Debuggowanie

Mając już all w repozytorium jak i z deployowane i przynajmniej raz odpalone to możemy testować.  W tym celu w menu dostępnych aplikacji wybieramy Debug:

Opcja Debug w menu
Opcja Debug w menu

Ekran nas sam poprosi o dodanie kodu który ma zostać załadowany. Może to by repozytorium googla, github, bitbucket lub plik z naszego kompa. Skoro mamy kod w repo na google to skorzystajmy z tego:

Wybór repozytorium w oknie Debug
Wybór repozytorium w oknie Debug

Dzięki któremu nasz kod będzie dostępny na ekranie.

Okno z załadowany kodem snapshot i logpoint'ami
Okno z załadowany kodem snapshot i logpoint’ami

Następnie trzeba wybrać odpowiedni worker (jeżeli odpaliliśmy naszą funkcję to będzie worker):

Wybór workera
Wybór workera

Mając tak wybrane opcje, możemy zacząć się bawić dwoma opcjami testowania/debugowania kodu jakie są dostępne:

  • Snapshot
  • Logpoint

To czy działamy w kontekście snapshota czy logpointa określna wybrana zakładka po prawej stronie:

Snapshot albo Logpoint
Snapshot albo Logpoint

To też jest ważne na której zakładce jesteśmy w trakcie wykonywania zapytania do naszej funkcji. Gdyż jeżeli będziemy na logpoint, to dane ze snapshot nie zostaną przechwycone. Zaś jak jesteśmy na snapshot to logpointy działają, ale nie możemy ich ustawiać.

Snapshoty

Snapshot to jak sama nazwa wskazuje, migawka z wykonania naszej funkcji w danym miejscu. To znaczy, jeżeli ustawimy breakpoint na linijce 12 to jak wykonamy naszą funkcję, ten breakpoint będzie zawierał informacje o całym kontekście danej funkcji: zmienne lokalne, parametry funkcji jak i stack trace.

Ważne jest by pamiętać, że to nie jest prawdziwy breakpoint ale po prostu miejsce w którym robiony jest snapshot. Narzut na wydajność jest niski, tak jakby bardziej zaawansowany jakiś log. Ale przynajmniej funkcja nie jest blokowana do póki nie zwolnimy jej z procesu debugowania.

Ustawienie i odczytanie Snapshot
Ustawienie i odczytanie Snapshot

Logpointy

Logpointy to nic innego jak dodatkowe logowanie które możemy dodać do już istniejącej funkcji nie zmieniając jej kodu źródłowego. To znaczy, mamy jakiś problem, nie wiem zbytnio o co chodzi, dodajemy kilka dodatkowych logów i boom, już wiemy, że to jest jakiś dziwny przypadek i że snapshot się nam przyda :)

W logpointy ustawiamy podobnie jak breakpointy. Ale z tą różnicą iż będziemy podawać warunek kiedy ma być coś zalogowane oraz co ma być zalogowane:

Ustawienie logpoints
Ustawienie logpoints

Każdy taki log trafia do globalnego logowania wykonania funkcji. Można go przejrzeć w log viewer – link jest dostępny w dolnym panelu w zakładce Logs. Na razie jeszcze nie możemy tego przeglądać w oknie Debug. Przynajmniej dla cloud functions.

Taki log wygląda mniej więcej tak:

Wpis logpoint w logu
Wpis logpoint w logu

I zawiera takie informacje:

{
 insertId:  "000000-9e17da84-4649-495d-9fc4-addf7c091706"  
 labels: {
  execution_id:  "36fjd5rm36t5"   
 }
 logName:  "projects/func-tests/logs/cloudfunctions.googleapis.com%2Fcloud-functions"  
 payload:  "LOGPOINT: his name is "gutek""  
 receiveTimestamp:  "2017-07-26T14:59:56.405687048Z"  
 resource: {
  labels: {
   function_name:  "debugWorld"    
   project_id:  "func-tests"    
   region:  "us-central1"    
  }
  type:  "cloud_function"   
 }
 severity:  "INFO"  
 textPayload:  "LOGPOINT: his name is "gutek""  
 timestamp:  "2017-07-26T14:59:46.364Z"  
}

Jest jednak małe ale. Nie działały mi typy logpointów. Czy to był warning czy error, zawsze logowało się jako info. Może to naprawią a może tak ma być. Nie wiem.

Podsumowanie

To tyle co miałem dzisiaj do pokazania. Mi się osobiście funkcjonalność bardzo, ale to bardzo spodobała. Po pierwsze, wiem jak trudno jest czasami coś z produkcji wyciągnąć i wgrywanie częste nowego kodu by coś ekstra wyciągnąć nie należy do dobrych rozwiązań. Po drugie podoba mi się opcja debugowania bez zatrzymywania procesu. Nie jest to coś z czego zawsze będziemy korzystać. Ale kiedy coś pójdzie nie tak, te funkcję mogą uratować nam tyłek.

Jestem ciekawe czy mieliście przypadek by takie logowanie/debugowanie by was uratowało/wspomogło/przyspieszyło rozwiązanie problemu? Co sądzicie o takiej opcji jaką daje google, fajna? Niefajna?

PS.: Z góry napiszę, nie wiem co oferuje Application Insights więc ciężko się mi do tego odnieść. Możliwe, że MS też ma taką funkcję :)

1 KOMENTARZ

  1. Serverless – Non-blocking debugowanie na produkcji (Cloud Functions Część 3) – Jakub Gutkowski

    Dziękujemy za dodanie artykułu – Trackback z dotnetomaniak.pl

Comments are closed.