Teknik observasi praktis untuk aplikasi AI Generatif di Go

1. Ringkasan

Aplikasi AI generatif memerlukan kemampuan observasi seperti aplikasi lainnya. Apakah ada teknik pengamatan khusus yang diperlukan untuk AI Generatif?

Di lab ini, Anda akan membuat aplikasi AI Generatif sederhana. Deploy ke Cloud Run. Selain itu, lengkapi dengan kemampuan pemantauan dan logging penting menggunakan produk dan layanan observabilitas Google Cloud.

Yang akan Anda pelajari

  • Menulis aplikasi yang menggunakan Vertex AI dengan Cloud Shell Editor
  • Menyimpan kode aplikasi Anda di GitHub
  • Gunakan gcloud CLI untuk men-deploy kode sumber aplikasi Anda ke Cloud Run
  • Menambahkan kemampuan pemantauan dan logging ke aplikasi AI Generatif Anda
  • Menggunakan metrik berbasis log
  • Menerapkan logging dan pemantauan dengan Open Telemetry SDK
  • Mendapatkan insight tentang penanganan data AI yang bertanggung jawab

2. Prasyarat

Jika Anda belum memiliki Akun Google, Anda harus membuat akun baru.

3. Penyiapan project

  1. Login ke Konsol Google Cloud dengan Akun Google Anda.
  2. Buat project baru atau pilih untuk menggunakan kembali project yang ada. Tuliskan project ID dari project yang baru saja Anda buat atau pilih.
  3. Aktifkan penagihan untuk project.
    • Menyelesaikan lab ini akan dikenai biaya penagihan kurang dari $5.
    • Anda dapat mengikuti langkah-langkah di akhir lab ini untuk menghapus resource agar tidak dikenai biaya lebih lanjut.
    • Pengguna baru memenuhi syarat untuk mengikuti Uji Coba Gratis senilai$300 USD.
  4. Konfirmasi bahwa penagihan diaktifkan di Project saya di Penagihan Cloud
    • Jika project baru Anda bertuliskan Billing is disabled di kolom Billing account:
      1. Klik tiga titik di kolom Actions
      2. Klik Ubah penagihan
      3. Pilih akun penagihan yang ingin Anda gunakan
    • Jika Anda menghadiri acara live, akun tersebut kemungkinan akan diberi nama Akun Penagihan Uji Coba Google Cloud Platform

4. Menyiapkan Cloud Shell Editor

  1. Buka Cloud Shell Editor. Jika Anda diminta dengan pesan berikut, yang meminta untuk mengizinkan cloud shell memanggil gcloud dengan kredensial Anda, klik Authorize untuk melanjutkan.
    Klik untuk memberikan otorisasi pada Cloud Shell
  2. Buka jendela terminal
    1. Klik menu tiga garis Ikon menu tiga garis
    2. Klik Terminal
    3. Klik New Terminal
      Membuka terminal baru di Cloud Shell Editor
  3. Di terminal, konfigurasi project ID Anda:
    gcloud config set project [PROJECT_ID]
    
    Ganti [PROJECT_ID] dengan ID project Anda. Misalnya, jika project ID Anda adalah lab-example-project, perintahnya adalah:
    gcloud config set project lab-project-id-example
    
    Jika Anda melihat pesan berikut, yang menyatakan bahwa gcloud meminta kredensial Anda ke GCPI API, klik Authorize untuk melanjutkan.
    Klik untuk memberikan otorisasi pada Cloud Shell
    Setelah berhasil dieksekusi, Anda akan melihat pesan berikut:
    Updated property [core/project].
    
    Jika Anda melihat WARNING dan diminta Do you want to continue (Y/N)?, berarti Anda kemungkinan telah memasukkan ID project dengan salah. Tekan N, tekan Enter, lalu coba jalankan perintah gcloud config set project lagi setelah Anda menemukan project ID yang benar.
  4. (Opsional) Jika Anda mengalami masalah dalam menemukan project ID, jalankan perintah berikut untuk melihat project ID semua project Anda yang diurutkan berdasarkan waktu pembuatan dalam urutan menurun:
    gcloud projects list \
         --format='value(projectId,createTime)' \
         --sort-by=~createTime
    

5. Mengaktifkan Google API

Di terminal, aktifkan Google API yang diperlukan untuk lab ini:

gcloud services enable \
     run.googleapis.com \
     cloudbuild.googleapis.com \
     aiplatform.googleapis.com \
     logging.googleapis.com \
     monitoring.googleapis.com \
     cloudtrace.googleapis.com

Perintah ini akan memerlukan waktu beberapa saat untuk diselesaikan. Pada akhirnya, pesan sukses yang mirip dengan yang berikut ini akan ditampilkan:

Operation "operations/acf.p2-73d90d00-47ee-447a-b600" finished successfully.

Jika Anda menerima pesan error yang diawali dengan ERROR: (gcloud.services.enable) HttpError accessing dan berisi detail error seperti di bawah, coba lagi perintah setelah jeda 1-2 menit.

"error": {
  "code": 429,
  "message": "Quota exceeded for quota metric 'Mutate requests' and limit 'Mutate requests per minute' of service 'serviceusage.googleapis.com' ...",
  "status": "RESOURCE_EXHAUSTED",
  ...
}

6. Membuat aplikasi Go AI Generatif

Pada langkah ini, Anda akan menulis kode aplikasi sederhana berbasis permintaan yang menggunakan model Gemini untuk menampilkan 10 fakta menarik tentang hewan pilihan Anda. Lakukan langkah-langkah berikut untuk membuat kode aplikasi.

  1. Di terminal, buat direktori codelab-o11y:
    mkdir ~/codelab-o11y
    
  2. Ubah direktori saat ini menjadi codelab-o11y:
    cd ~/codelab-o11y
    
  3. Lakukan inisialisasi modul Go:
    go mod init codelab
    
  4. Instal Vertex AI SDK untuk Go:
    go get cloud.google.com/go/vertexai/genai
    
  5. Instal library Metadata untuk Go guna mendapatkan project ID saat ini:
    go get cloud.google.com/go/compute/metadata
    
  6. Buat file setup.go dan buka file di Cloud Shell Editor:
    cloudshell edit setup.go
    
    Bucket ini akan digunakan untuk menghosting kode inisialisasi. File kosong baru dengan nama setup.go akan muncul di jendela editor.
  7. Salin kode berikut dan tempelkan ke dalam file setup.go yang terbuka:
    package main
    
    import (
        "context"
        "os"
    
        "cloud.google.com/go/compute/metadata"
    )
    
    func projectID(ctx context.Context) (string, error) {
        var projectID = os.Getenv("GOOGLE_CLOUD_PROJECT")
        if projectID == "" {
               return metadata.ProjectIDWithContext(ctx)
        }
        return projectID, nil
    }
    
  8. Kembali ke jendela terminal dan jalankan perintah berikut untuk membuat dan membuka file main.go di Cloud Shell Editor:
    cloudshell edit main.go
    
    File kosong akan muncul di jendela editor di atas terminal. Layar Anda akan terlihat seperti berikut:
    Menampilkan Cloud Shell Editor setelah mulai mengedit main.go
  9. Salin kode berikut dan tempelkan ke dalam file main.go yang terbuka:
    package main
    
    import (
        "context"
        "fmt"
        "net/http"
        "os"
    
        "cloud.google.com/go/vertexai/genai"
    )
    
    var model *genai.GenerativeModel
    
    func main() {
        ctx := context.Background()
        projectID, err := projectID(ctx)
        if err != nil {
            return
        }
    
        var client *genai.Client
        client, err = genai.NewClient(ctx, projectID, "us-central1")
        if err != nil {
            return
        }
        defer client.Close()
           model = client.GenerativeModel("gemini-1.5-flash-001")
           http.HandleFunc("/", Handler)
           port := os.Getenv("PORT")
        if port == "" {
            port = "8080"
        }
        if err := http.ListenAndServe(":"+port, nil); err != nil {
            return
        }
    }
    
    func Handler(w http.ResponseWriter, r *http.Request) {
        animal := r.URL.Query().Get("animal")
        if animal == "" {
            animal = "dog"
        }
    
        prompt := fmt.Sprintf("Give me 10 fun facts about %s. Return the results as HTML without markdown backticks.", animal)
        resp, err := model.GenerateContent(r.Context(), genai.Text(prompt))
        if err != nil {
            w.WriteHeader(http.StatusTooManyRequests)
            return
        }
    
        if len(resp.Candidates) > 0 && len(resp.Candidates[0].Content.Parts) > 0 {
            htmlContent := resp.Candidates[0].Content.Parts[0]
            w.Header().Set("Content-Type", "text/html; charset=utf-8")
            fmt.Fprint(w, htmlContent)
        }
    }
    
    Setelah beberapa detik, Cloud Shell Editor akan menyimpan kode Anda secara otomatis.

Men-deploy kode aplikasi AI Generatif ke Cloud Run

  1. Di jendela terminal, jalankan perintah untuk men-deploy kode sumber aplikasi ke Cloud Run.
    gcloud run deploy codelab-o11y-service \
         --source="${HOME}/codelab-o11y/" \
         --region=us-central1 \
         --allow-unauthenticated
    
    Jika Anda melihat perintah seperti di bawah, yang memberi tahu Anda bahwa perintah tersebut akan membuat repositori baru. Klik Enter.
    Deploying from source requires an Artifact Registry Docker repository to store built containers.
    A repository named [cloud-run-source-deploy] in region [us-central1] will be created.
    
    Do you want to continue (Y/n)?
    
    Proses deployment dapat memerlukan waktu hingga beberapa menit. Setelah proses deployment selesai, Anda akan melihat output seperti:
    Service [codelab-o11y-service] revision [codelab-o11y-service-00001-t2q] has been deployed and is serving 100 percent of traffic.
    Service URL: https://codelab-o11y-service-12345678901.us-central1.run.app
    
  2. Salin URL layanan Cloud Run yang ditampilkan ke tab atau jendela terpisah di browser Anda. Atau, jalankan perintah berikut di terminal untuk mencetak URL layanan dan klik URL yang ditampilkan sambil menahan tombol Ctrl untuk membuka URL:
    gcloud run services list \
         --format='value(URL)' \
         --filter='SERVICE:"codelab-o11y-service"'
    
    Saat URL dibuka, Anda mungkin mendapatkan error 500 atau melihat pesan:
    Sorry, this is just a placeholder...
    
    Artinya, layanan tidak menyelesaikan deployment-nya. Tunggu beberapa saat, lalu muat ulang halaman. Di akhir, Anda akan melihat teks yang dimulai dengan Fakta Menarik tentang dan berisi 10 fakta menarik tentang.

Coba berinteraksi dengan aplikasi untuk mendapatkan fakta menarik tentang berbagai hewan. Untuk melakukannya, tambahkan parameter animal ke URL, seperti ?animal=[ANIMAL] dengan [ANIMAL] adalah nama hewan. Misalnya, tambahkan ?animal=cat untuk mendapatkan 10 fakta menarik tentang kucing atau ?animal=sea turtle untuk mendapatkan 10 fakta menarik tentang penyu.

7. Mengaudit panggilan Vertex API Anda

Mengaudit panggilan Google API memberikan jawaban atas pertanyaan seperti "Siapa yang memanggil API tertentu, di mana, dan kapan?". Audit penting saat Anda memecahkan masalah aplikasi, menyelidiki konsumsi resource, atau melakukan analisis forensik software.

Log audit memungkinkan Anda melacak aktivitas administratif dan sistem, serta mencatat panggilan ke operasi API "baca data" dan "tulis data". Untuk mengaudit permintaan Vertex AI guna membuat konten, Anda harus mengaktifkan log audit "Data Read" di Konsol Cloud.

  1. Klik tombol di bawah untuk membuka halaman Log Audit di Konsol Cloud

  2. Pastikan halaman menampilkan project yang Anda buat untuk lab ini. Project yang dipilih ditampilkan di pojok kiri atas halaman tepat dari menu hamburger:
    Dropdown project Google Cloud Console
    Jika perlu, pilih project yang benar dari kotak kombinasi.
  3. Di tabel Konfigurasi log audit Akses Data, di kolom Layanan, temukan layanan Vertex AI API dan pilih layanan tersebut dengan mencentang kotak yang berada di sebelah kiri nama layanan.
    Pilih Vertex AI API
  4. Di panel info di sebelah kanan, pilih jenis audit "Data Read".
    Memeriksa log Pembacaan Data
  5. Klik Simpan.

Untuk membuat log audit, buka URL layanan. Muat ulang halaman sambil mengubah nilai parameter ?animal= untuk mendapatkan hasil yang berbeda.

Menjelajahi log audit

  1. Klik tombol di bawah untuk membuka halaman Logs Explorer di konsol Cloud:

  2. Tempel filter berikut ke panel Kueri.
    LOG_ID("cloudaudit.googleapis.com%2Fdata_access") AND
    protoPayload.serviceName="aiplatform.googleapis.com"
    
    Panel Kueri adalah editor yang terletak di dekat bagian atas halaman Logs Explorer:
    Membuat kueri log audit
  3. Klik Run query.
  4. Pilih salah satu entri log audit dan luaskan kolom untuk memeriksa informasi yang tercatat dalam log.
    Anda dapat melihat detail tentang panggilan Vertex API, termasuk metode dan model yang digunakan. Anda juga dapat melihat identitas pemanggil dan izin apa yang mengizinkan panggilan.

8. Mencatat interaksi dengan AI Generatif

Anda tidak akan menemukan parameter permintaan API atau data respons dalam log audit. Namun, informasi ini dapat menjadi penting untuk memecahkan masalah analisis aplikasi dan alur kerja. Pada langkah ini, kita akan mengisi kesenjangan ini dengan menambahkan logging aplikasi. Logging menggunakan paket log/slog Go standar untuk menulis log terstruktur. Paket log/slog tidak tahu cara menulis log ke Google Cloud. Mendukung penulisan ke output standar. Namun, Cloud Run memiliki fitur yang secara otomatis mengambil informasi yang dicetak ke output standar dan menyerapnya ke Cloud Logging. Untuk merekam log terstruktur dengan benar, log yang dicetak harus diformat dengan tepat. Ikuti petunjuk di bawah untuk menambahkan kemampuan logging terstruktur ke aplikasi Go kita.

  1. Kembali ke jendela (atau tab) 'Cloud Shell' di browser Anda.
  2. Di terminal, buka kembali setup.go:
    cloudshell edit ~/codelab-o11y/setup.go
    
  3. Ganti kode dengan versi yang menyiapkan logging. Untuk mengganti kode, hapus konten file, lalu salin kode di bawah dan tempelkan ke editor:
    package main
    
    import (
    	"context"
    	"os"
    	"log/slog"
    	"cloud.google.com/go/compute/metadata"
    )
    
    func projectID(ctx context.Context) (string, error) {
        var projectID = os.Getenv("GOOGLE_CLOUD_PROJECT")
        if projectID == "" {
               return metadata.ProjectIDWithContext(ctx)
        }
        return projectID, nil
    }
    
    func setupLogging() {
        opts := &slog.HandlerOptions{
            Level: slog.LevelDebug,
            ReplaceAttr: func(group []string, a slog.Attr) slog.Attr {
                switch a.Key {
                case slog.LevelKey:
                    a.Key = "severity"
                    if level := a.Value.Any().(slog.Level); level == slog.LevelWarn {
                        a.Value = slog.StringValue("WARNING")
                    }
                case slog.MessageKey:
                    a.Key = "message"
                case slog.TimeKey:
                    a.Key = "timestamp"
                }
                return a
            },
        }
        jsonHandler := slog.NewJSONHandler(os.Stdout, opts)
        slog.SetDefault(slog.New(jsonHandler))
    }
    
  4. Kembali ke terminal, lalu buka kembali main.go:
    cloudshell edit ~/codelab-o11y/main.go
    
  5. Ganti kode aplikasi dengan versi yang mencatat interaksi dengan model. Untuk mengganti kode, hapus konten file, lalu salin kode di bawah dan tempelkan ke editor:
    package main
    
    import (
        "context"
        "fmt"
        "net/http"
        "os"
    
        "encoding/json"
        "log/slog"
    
        "cloud.google.com/go/vertexai/genai"
    )
    
    var model *genai.GenerativeModel
    
    func main() {
        ctx := context.Background()
        projectID, err := projectID(ctx)
        if err != nil {
            return
        }
    
        setupLogging()
    
        var client *genai.Client
        client, err = genai.NewClient(ctx, projectID, "us-central1")
        if err != nil {
            slog.ErrorContext(ctx, "Failed to marshal response to JSON", slog.Any("error", err))
            os.Exit(1)
        }
        defer client.Close()
        model = client.GenerativeModel("gemini-1.5-flash-001")
        http.HandleFunc("/", Handler)
        port := os.Getenv("PORT")
        if port == "" {
            port = "8080"
        }
        if err := http.ListenAndServe(":"+port, nil); err != nil {
            slog.ErrorContext(ctx, "Failed to start the server", slog.Any("error", err))
            os.Exit(1)
        }
    }
    
    func Handler(w http.ResponseWriter, r *http.Request) {
        animal := r.URL.Query().Get("animal")
        if animal == "" {
            animal = "dog"
        }
    
        prompt := fmt.Sprintf("Give me 10 fun facts about %s. Return the results as HTML without markdown backticks.", animal)
        resp, err := model.GenerateContent(r.Context(), genai.Text(prompt))
        if err != nil {
            w.WriteHeader(http.StatusTooManyRequests)
            return
        }
    
        jsonBytes, err := json.Marshal(resp)
        if err != nil {
            slog.Error("Failed to marshal response to JSON", slog.Any("error", err))
        } else {
            slog.DebugContext(r.Context(), "content is generated", slog.String("animal", animal),
                slog.String("prompt", prompt), slog.String("response", string(jsonBytes)))
        }
    
        if len(resp.Candidates) > 0 && len(resp.Candidates[0].Content.Parts) > 0 {
            htmlContent := resp.Candidates[0].Content.Parts[0]
            w.Header().Set("Content-Type", "text/html; charset=utf-8")
            fmt.Fprint(w, htmlContent)
        }
    }
    

Logging dikonfigurasi untuk mencetak log ke stdout tempat log dikumpulkan oleh agen logging Cloud Run dan dimasukkan secara asinkron ke Cloud Logging. Fungsi main() diubah untuk menyiapkan log terstruktur standar Go agar menggunakan skema JSON yang mengikuti panduan pemformatan terstruktur. Semua pernyataan return-nya diganti dengan kode yang menulis log error sebelum keluar. Fungsi Handler() diinstrumentasikan untuk menulis log terstruktur saat menerima respons dari panggilan Vertex AI API. Log mencatat parameter hewan dari permintaan serta perintah dan respons model.

Setelah beberapa detik, Cloud Shell Editor akan menyimpan perubahan Anda secara otomatis.

Men-deploy kode aplikasi AI Generatif ke Cloud Run

  1. Di jendela terminal, jalankan perintah untuk men-deploy kode sumber aplikasi ke Cloud Run.
    gcloud run deploy codelab-o11y-service \
         --source="${HOME}/codelab-o11y/" \
         --region=us-central1 \
         --allow-unauthenticated
    
    Jika Anda melihat perintah seperti di bawah, yang memberi tahu Anda bahwa perintah tersebut akan membuat repositori baru. Klik Enter.
    Deploying from source requires an Artifact Registry Docker repository to store built containers.
    A repository named [cloud-run-source-deploy] in region [us-central1] will be created.
    
    Do you want to continue (Y/n)?
    
    Proses deployment dapat memerlukan waktu hingga beberapa menit. Setelah proses deployment selesai, Anda akan melihat output seperti:
    Service [codelab-o11y-service] revision [codelab-o11y-service-00001-t2q] has been deployed and is serving 100 percent of traffic.
    Service URL: https://codelab-o11y-service-12345678901.us-central1.run.app
    
  2. Salin URL layanan Cloud Run yang ditampilkan ke tab atau jendela terpisah di browser Anda. Atau, jalankan perintah berikut di terminal untuk mencetak URL layanan dan klik URL yang ditampilkan sambil menahan tombol Ctrl untuk membuka URL:
    gcloud run services list \
         --format='value(URL)' \
         --filter='SERVICE:"codelab-o11y-service"'
    
    Saat URL dibuka, Anda mungkin mendapatkan error 500 atau melihat pesan:
    Sorry, this is just a placeholder...
    
    Artinya, layanan tidak menyelesaikan deployment-nya. Tunggu beberapa saat, lalu muat ulang halaman. Di akhir, Anda akan melihat teks yang dimulai dengan Fakta Menarik tentang dan berisi 10 fakta menarik tentang.

Untuk membuat log aplikasi, buka URL layanan. Muat ulang halaman sambil mengubah nilai parameter ?animal= untuk mendapatkan hasil yang berbeda.
Untuk melihat log aplikasi, lakukan hal berikut:

  1. Klik tombol di bawah untuk membuka halaman Logs Explorer di Konsol Cloud:

  2. Tempel filter berikut ke panel Kueri (#2 di antarmuka Log explorer):
    LOG_ID("run.googleapis.com%2Fstdout") AND
    severity=DEBUG
    
  3. Klik Run query.

Hasil kueri menampilkan log dengan prompt dan respons Vertex AI, termasuk peringkat keamanan.

9. Menghitung interaksi dengan AI Generatif

Cloud Run menulis metrik terkelola yang dapat digunakan untuk memantau layanan yang di-deploy. Metrik pemantauan yang dikelola pengguna memberikan kontrol yang lebih besar atas data dan frekuensi pembaruan metrik. Untuk menerapkan metrik tersebut, Anda perlu menulis kode yang mengumpulkan data dan menuliskannya ke Cloud Monitoring. Lihat langkah berikutnya (opsional) untuk mengetahui cara menerapkannya menggunakan OpenTelemetry SDK.

Langkah ini menunjukkan alternatif untuk menerapkan metrik pengguna dalam kode - metrik berbasis log. Metrik berbasis log memungkinkan Anda membuat metrik pemantauan dari entri log yang ditulis aplikasi Anda ke Cloud Logging. Kita akan menggunakan log aplikasi yang kita terapkan di langkah sebelumnya untuk menentukan metrik berbasis log dari penghitung jenis. Metrik ini akan menghitung jumlah panggilan yang berhasil ke Vertex API.

  1. Lihat jendela Logs Explorer yang kita gunakan pada langkah sebelumnya. Di bagian panel Kueri, cari menu drop-down Tindakan, lalu klik untuk membukanya. Lihat screenshot di bawah untuk menemukan menu:
    Toolbar hasil kueri dengan menu drop-down Tindakan
  2. Di menu yang terbuka, pilih Create metric untuk membuka panel Create log-based metric.
  3. Ikuti langkah-langkah berikut untuk mengonfigurasi metrik penghitung baru di panel Buat metrik berbasis log:
    1. Tetapkan Jenis metrik: Pilih Penghitung.
    2. Tetapkan kolom berikut di bagian Detail:
      • Nama metrik log: Tetapkan nama ke model_interaction_count. Beberapa batasan penamaan berlaku; Lihat Pemecahan masalah batasan penamaan untuk mengetahui detailnya.
      • Deskripsi: Masukkan deskripsi untuk metrik. Misalnya, Number of log entries capturing successful call to model inference.
      • Unit: Biarkan kosong atau masukkan digit 1.
    3. Biarkan nilai di bagian Filter selection. Perhatikan bahwa kolom Build filter memiliki filter yang sama dengan yang kita gunakan untuk melihat log aplikasi.
    4. (Opsional) Tambahkan label yang membantu menghitung jumlah panggilan untuk setiap hewan. CATATAN: label ini berpotensi meningkatkan kardinalitas metrik secara signifikan dan tidak direkomendasikan untuk digunakan dalam produksi:
      1. Klik Tambahkan label.
      2. Tetapkan kolom berikut di bagian Label:
        • Nama label: Tetapkan nama ke animal.
        • Deskripsi: Masukkan deskripsi label. Misalnya, Animal parameter.
        • Jenis label: Pilih STRING.
        • Nama kolom: Ketik jsonPayload.animal.
        • Ekspresi reguler: Biarkan kosong.
      3. Klik Selesai
    5. Klik Buat metrik untuk membuat metrik.

Anda juga dapat membuat metrik berbasis log dari halaman Metrik berbasis log, menggunakan gcloud logging metrics create perintah CLI atau dengan google_logging_metric resource Terraform.

Untuk membuat data metrik, buka URL layanan. Muat ulang halaman yang dibuka beberapa kali untuk melakukan beberapa panggilan ke model. Seperti sebelumnya, coba gunakan hewan yang berbeda dalam parameter.

Masukkan kueri PromQL untuk menelusuri data metrik berbasis log. Untuk memasukkan kueri PromQL, lakukan hal berikut:

  1. Klik tombol di bawah untuk membuka halaman Metrics explorer di Konsol Cloud:

  2. Di toolbar panel pembuat kueri, pilih tombol yang namanya < > MQL atau < > PromQL. Lihat gambar di bawah untuk mengetahui lokasi tombol.
    Lokasi tombol MQL di Metrics Explorer
  3. Pastikan PromQL dipilih di tombol Language. Tombol bahasa ada di toolbar yang sama yang memungkinkan Anda memformat kueri.
  4. Masukkan kueri Anda ke editor Queries:
    sum(rate(logging_googleapis_com:user_model_interaction_count{monitored_resource="cloud_run_revision"}[${__interval}]))
    
    Untuk mengetahui informasi selengkapnya tentang penggunaan PromQL, lihat PromQL di Cloud Monitoring.
  5. Klik Run Query. Anda akan melihat diagram garis yang mirip dengan screenshot ini:
    Menampilkan metrik yang dikueri

    Perhatikan bahwa saat tombol Jalankan otomatis diaktifkan, tombol Jalankan Kueri tidak ditampilkan.

10. (Opsional) Menggunakan Open Telemetry untuk pemantauan dan perekaman aktivitas

Seperti yang disebutkan pada langkah sebelumnya, metrik dapat diterapkan menggunakan OpenTelemetry (Otel) SDK. Menggunakan OTel pada arsitektur microservice adalah praktik yang direkomendasikan. Langkah ini menjelaskan hal berikut:

  • Menginisialisasi komponen OTel untuk mendukung pelacakan dan pemantauan aplikasi
  • Mengisi konfigurasi OTel dengan metadata resource lingkungan Cloud Run
  • Menginstrumentasi aplikasi flask dengan kemampuan pelacakan otomatis
  • Menerapkan metrik penghitung untuk memantau jumlah panggilan model yang berhasil
  • Menghubungkan rekaman aktivitas dengan log aplikasi

Arsitektur yang direkomendasikan untuk layanan tingkat produk adalah menggunakan pengumpul OTel untuk mengumpulkan dan menyerap semua data keobservasian untuk satu atau beberapa layanan. Kode dalam langkah ini tidak menggunakan pengumpul agar lebih praktis. Sebagai gantinya, library ini menggunakan ekspor OTel yang menulis data langsung ke Google Cloud.

Menyiapkan komponen OTel untuk pelacakan dan pemantauan metrik

  1. Kembali ke jendela (atau tab) 'Cloud Shell' di browser Anda.
  2. Di terminal, buka kembali setup.go:
    cloudshell edit ~/codelab-o11y/setup.go
    
  3. Ganti kode dengan versi yang menginisialisasi pengumpulan metrik dan pelacakan OpenTelemetry. Untuk mengganti kode, hapus konten file, lalu salin kode di bawah dan tempelkan ke editor:
    package main
    
    import (
        "context"
        "errors"
        "fmt"
        "net/http"
        "os"
    
        "log/slog"
    
        "go.opentelemetry.io/contrib/detectors/gcp"
        "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
        "go.opentelemetry.io/contrib/propagators/autoprop"
        "go.opentelemetry.io/otel"
        sdkmetric "go.opentelemetry.io/otel/sdk/metric"
        "go.opentelemetry.io/otel/sdk/resource"
        sdktrace "go.opentelemetry.io/otel/sdk/trace"
        semconv "go.opentelemetry.io/otel/semconv/v1.27.0"
        "go.opentelemetry.io/otel/trace"
    
        cloudmetric "github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric"
        cloudtrace "github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace"
    
        "cloud.google.com/go/compute/metadata"
    )
    
    var (
        projID string
    )
    
    func projectID(ctx context.Context) (string, error) {
        var projectID = os.Getenv("GOOGLE_CLOUD_PROJECT")
        if projectID == "" {
            return metadata.ProjectIDWithContext(ctx)
        }
        return projectID, nil
    }
    
    func setupLogging() {
        opts := &slog.HandlerOptions{
            Level: slog.LevelDebug,
            ReplaceAttr: func(group []string, a slog.Attr) slog.Attr {
                switch a.Key {
                case slog.LevelKey:
                    a.Key = "severity"
                    if level := a.Value.Any().(slog.Level); level == slog.LevelWarn {
                        a.Value = slog.StringValue("WARNING")
                    }
                case slog.MessageKey:
                    a.Key = "message"
                case slog.TimeKey:
                    a.Key = "timestamp"
                }
                return a
            },
        }
        jsonHandler := slog.NewJSONHandler(os.Stdout, opts)
        instrumentedHandler := handlerWithSpanContext(jsonHandler)
        slog.SetDefault(slog.New(instrumentedHandler))
    }
    
    type spanContextLogHandler struct {
        slog.Handler
    }
    
    func handlerWithSpanContext(handler slog.Handler) *spanContextLogHandler {
        return &spanContextLogHandler{Handler: handler}
    }
    
    func (t *spanContextLogHandler) Handle(ctx context.Context, record slog.Record) error {
        if s := trace.SpanContextFromContext(ctx); s.IsValid() {
            trace := fmt.Sprintf("projects/%s/traces/%s", projID, s.TraceID())
            record.AddAttrs(
                slog.Any("logging.googleapis.com/trace", trace),
            )
            record.AddAttrs(
                slog.Any("logging.googleapis.com/spanId", s.SpanID()),
            )
            record.AddAttrs(
                slog.Bool("logging.googleapis.com/trace_sampled", s.TraceFlags().IsSampled()),
            )
        }
        return t.Handler.Handle(ctx, record)
    }
    
    func setupTelemetry(ctx context.Context) (shutdown func(context.Context) error, err error) {
        var shutdownFuncs []func(context.Context) error
        shutdown = func(ctx context.Context) error {
            var err error
            for _, fn := range shutdownFuncs {
                err = errors.Join(err, fn(ctx))
            }
            shutdownFuncs = nil
            return err
        }
    
        projID, err = projectID(ctx)
        if err != nil {
            err = errors.Join(err, shutdown(ctx))
            return
        }
    
        res, err2 := resource.New(
            ctx,
            resource.WithDetectors(gcp.NewDetector()),
            resource.WithTelemetrySDK(),
            resource.WithAttributes(semconv.ServiceNameKey.String(os.Getenv("K_SERVICE"))),
        )
        if err2 != nil {
            err = errors.Join(err2, shutdown(ctx))
            return
        }
    
        otel.SetTextMapPropagator(autoprop.NewTextMapPropagator())
    
        texporter, err2 := cloudtrace.New(cloudtrace.WithProjectID(projID))
        if err2 != nil {
            err = errors.Join(err2, shutdown(ctx))
            return
        }
        tp := sdktrace.NewTracerProvider(
            sdktrace.WithSampler(sdktrace.AlwaysSample()),
            sdktrace.WithResource(res),
            sdktrace.WithBatcher(texporter))
        shutdownFuncs = append(shutdownFuncs, tp.Shutdown)
        otel.SetTracerProvider(tp)
    
        mexporter, err2 := cloudmetric.New(cloudmetric.WithProjectID(projID))
        if err2 != nil {
            err = errors.Join(err2, shutdown(ctx))
            return
        }
        mp := sdkmetric.NewMeterProvider(
            sdkmetric.WithReader(sdkmetric.NewPeriodicReader(mexporter)),
            sdkmetric.WithResource(res),
        )
        shutdownFuncs = append(shutdownFuncs, mp.Shutdown)
        otel.SetMeterProvider(mp)
    
        return shutdown, nil
    }
    
    func registerHttpHandler(route string, handleFn http.HandlerFunc) {
        instrumentedHandler := otelhttp.NewHandler(otelhttp.WithRouteTag(route, handleFn), route)
        http.Handle(route, instrumentedHandler)
    }
    
  4. Kembali ke terminal dan jalankan perintah berikut untuk memperbarui definisi modul Go dalam file go.mod:
    go mod tidy
    
  5. Kembali ke terminal, lalu buka kembali main.go:
    cloudshell edit ~/codelab-o11y/main.go
    
  6. Ganti kode saat ini dengan versi yang menginstrumentasi pelacakan HTTP dan menulis metrik performa. Untuk mengganti kode, hapus konten file, lalu salin kode di bawah dan tempelkan ke editor:
    package main
    
    import (
        "context"
        "errors"
        "fmt"
        "net/http"
        "os"
    
        "encoding/json"
        "log/slog"
    
        "cloud.google.com/go/vertexai/genai"
    
        "go.opentelemetry.io/otel"
        "go.opentelemetry.io/otel/attribute"
        "go.opentelemetry.io/otel/metric"
    )
    
    var model *genai.GenerativeModel
    var counter metric.Int64Counter
    
    const scopeName = "genai-o11y/go/workshop/example"
    
    func main() {
        ctx := context.Background()
        projectID, err := projectID(ctx)
        if err != nil {
            return
        }
    
        setupLogging()
        shutdown, err := setupTelemetry(ctx)
        if err != nil {
            slog.ErrorContext(ctx, "error setting up OpenTelemetry", slog.Any("error", err))
            os.Exit(1)
        }
        meter := otel.Meter(scopeName)
        counter, err = meter.Int64Counter("model_call_counter")
        if err != nil {
            slog.ErrorContext(ctx, "error setting up OpenTelemetry", slog.Any("error", err))
            os.Exit(1)
        }
    
        var client *genai.Client
        client, err = genai.NewClient(ctx, projectID, "us-central1")
        if err != nil {
            slog.ErrorContext(ctx, "Failed to marshal response to JSON", slog.Any("error", err))
            os.Exit(1)
        }
        defer client.Close()
        model = client.GenerativeModel("gemini-1.5-flash-001")
    
        registerHttpHandler("/", Handler)
    
        port := os.Getenv("PORT")
        if port == "" {
            port = "8080"
        }
    
        if err = errors.Join(http.ListenAndServe(":"+port, nil), shutdown(ctx)); err != nil {
            slog.ErrorContext(ctx, "Failed to start the server", slog.Any("error", err))
            os.Exit(1)
        }
    }
    
    func Handler(w http.ResponseWriter, r *http.Request) {
        animal := r.URL.Query().Get("animal")
        if animal == "" {
            animal = "dog"
        }
    
        prompt := fmt.Sprintf("Give me 10 fun facts about %s. Return the results as HTML without markdown backticks.", animal)
        resp, err := model.GenerateContent(r.Context(), genai.Text(prompt))
        if err != nil {
            w.WriteHeader(http.StatusTooManyRequests)
            return
        }
        jsonBytes, err := json.Marshal(resp)
        if err != nil {
            slog.ErrorContext(r.Context(), "Failed to marshal response to JSON", slog.Any("error", err))
        } else {
            slog.DebugContext(r.Context(), "content is generated", slog.String("animal", animal),
                slog.String("prompt", prompt), slog.String("response", string(jsonBytes)))
        }
        if len(resp.Candidates) > 0 && len(resp.Candidates[0].Content.Parts) > 0 {
            clabels := []attribute.KeyValue{attribute.Key("animal").String(animal)}
            counter.Add(r.Context(), 1, metric.WithAttributes(clabels...))
            htmlContent := resp.Candidates[0].Content.Parts[0]
            w.Header().Set("Content-Type", "text/html; charset=utf-8")
            fmt.Fprint(w, htmlContent)
        }
    }
    

Aplikasi kini menggunakan OpenTelemetry SDK untuk mengukur eksekusi kode dengan tracing dan menerapkan penghitungan jumlah eksekusi yang berhasil sebagai metrik. Metode main() diubah untuk menyiapkan pengekspor OpenTelemetry untuk trace dan metrik agar dapat menulis langsung ke Google Cloud Tracing dan Monitoring. Selain itu, library ini melakukan konfigurasi tambahan untuk mengisi data metrik dan rekaman aktivitas yang dikumpulkan dengan metadata terkait lingkungan Cloud Run. Fungsi Handler() diperbarui untuk menambah penghitung metrik setiap kali panggilan Vertex AI API menampilkan hasil yang valid.

Setelah beberapa detik, Cloud Shell Editor akan menyimpan perubahan Anda secara otomatis.

Men-deploy kode aplikasi AI Generatif ke Cloud Run

  1. Di jendela terminal, jalankan perintah untuk men-deploy kode sumber aplikasi ke Cloud Run.
    gcloud run deploy codelab-o11y-service \
         --source="${HOME}/codelab-o11y/" \
         --region=us-central1 \
         --allow-unauthenticated
    
    Jika Anda melihat perintah seperti di bawah, yang memberi tahu Anda bahwa perintah tersebut akan membuat repositori baru. Klik Enter.
    Deploying from source requires an Artifact Registry Docker repository to store built containers.
    A repository named [cloud-run-source-deploy] in region [us-central1] will be created.
    
    Do you want to continue (Y/n)?
    
    Proses deployment dapat memerlukan waktu hingga beberapa menit. Setelah proses deployment selesai, Anda akan melihat output seperti:
    Service [codelab-o11y-service] revision [codelab-o11y-service-00001-t2q] has been deployed and is serving 100 percent of traffic.
    Service URL: https://codelab-o11y-service-12345678901.us-central1.run.app
    
  2. Salin URL layanan Cloud Run yang ditampilkan ke tab atau jendela terpisah di browser Anda. Atau, jalankan perintah berikut di terminal untuk mencetak URL layanan dan klik URL yang ditampilkan sambil menahan tombol Ctrl untuk membuka URL:
    gcloud run services list \
         --format='value(URL)' \
         --filter='SERVICE:"codelab-o11y-service"'
    
    Saat URL dibuka, Anda mungkin mendapatkan error 500 atau melihat pesan:
    Sorry, this is just a placeholder...
    
    Artinya, layanan tidak menyelesaikan deployment-nya. Tunggu beberapa saat, lalu muat ulang halaman. Di akhir, Anda akan melihat teks yang dimulai dengan Fakta Menarik tentang dan berisi 10 fakta menarik tentang.

Untuk membuat data telemetri, buka URL layanan. Muat ulang halaman sambil mengubah nilai parameter ?animal= untuk mendapatkan hasil yang berbeda.

Menjelajahi rekaman aktivitas aplikasi

  1. Klik tombol di bawah untuk membuka halaman Trace Explorer di Konsol Cloud:

  2. Pilih salah satu rekaman aktivitas terbaru. Anda akan melihat 5 atau 6 rentang yang terlihat seperti pada screenshot di bawah.
    Tampilan rentang aplikasi di Trace Explorer
  3. Temukan rentang yang melacak panggilan ke pengendali peristiwa (metode fun_facts). Ini akan menjadi rentang terakhir dengan nama /.
  4. Di panel Detail rekaman aktivitas, pilih Log & peristiwa. Anda akan melihat log aplikasi yang berkorelasi dengan rentang tertentu ini. Korelasi terdeteksi menggunakan ID trace dan span dalam trace dan dalam log. Anda akan melihat log aplikasi yang menulis perintah dan respons Vertex API.

Mempelajari metrik penghitung

  1. Klik tombol di bawah untuk membuka halaman Metrics explorer di Konsol Cloud:

  2. Di toolbar panel pembuat kueri, pilih tombol yang namanya < > MQL atau < > PromQL. Lihat gambar di bawah untuk mengetahui lokasi tombol.
    Lokasi tombol MQL di Metrics Explorer
  3. Pastikan PromQL dipilih di tombol Language. Tombol bahasa ada di toolbar yang sama yang memungkinkan Anda memformat kueri.
  4. Masukkan kueri Anda ke editor Queries:
    sum(rate(workload_googleapis_com:model_call_counter{monitored_resource="generic_task"}[${__interval}]))
    
  5. Klik Run Query.Jika tombol Auto-run diaktifkan, tombol Run Query tidak akan ditampilkan.

11. (Opsional) Informasi sensitif yang di-obfuscate dari log

Pada Langkah 10, kita mencatat informasi tentang interaksi aplikasi dengan model Gemini. Informasi ini mencakup nama hewan, perintah sebenarnya, dan respons model. Meskipun menyimpan informasi ini dalam log seharusnya aman, hal ini tidak selalu benar untuk banyak skenario lainnya. Perintah dapat mencakup beberapa informasi pribadi atau sensitif lainnya yang tidak ingin disimpan oleh pengguna. Untuk mengatasi hal ini, Anda dapat meng-obfuscate data sensitif yang ditulis ke Cloud Logging. Untuk meminimalkan modifikasi kode, sebaiknya gunakan solusi berikut.

  1. Buat topik PubSub untuk menyimpan entri log masuk
  2. Buat sink log yang mengalihkan log yang di-ingest ke topik PubSub.
  3. Buat pipeline Dataflow yang mengubah log yang dialihkan ke topik PubSub dengan mengikuti langkah-langkah berikut:
    1. Membaca entri log dari topik PubSub
    2. Periksa payload entri untuk menemukan informasi sensitif menggunakan DLP inspection API
    3. Samarkan informasi sensitif dalam payload menggunakan salah satu metode penyamaran DLP
    4. Menulis entri log yang di-obfuscate ke Cloud Logging
  4. Men-deploy pipeline

12. (Opsional) Membersihkan

Untuk menghindari risiko dikenai biaya untuk resource dan API yang digunakan dalam codelab, sebaiknya lakukan pembersihan setelah Anda menyelesaikan lab. Cara termudah untuk menghilangkan penagihan adalah dengan menghapus project yang Anda buat untuk codelab.

  1. Untuk menghapus project, jalankan perintah hapus project di terminal:
    PROJECT_ID=$(gcloud config get-value project)
    gcloud projects delete ${PROJECT_ID} --quiet
    
    Menghapus project Cloud akan menghentikan penagihan untuk semua resource dan API yang digunakan dalam project tersebut. Anda akan melihat pesan ini dengan PROJECT_ID sebagai project ID Anda:
    Deleted [https://cloudresourcemanager.googleapis.com/v1/projects/PROJECT_ID].
    
    You can undo this operation for a limited period by running the command below.
        $ gcloud projects undelete PROJECT_ID
    
    See https://cloud.google.com/resource-manager/docs/creating-managing-projects for information on shutting down projects.
    
  2. (Opsional) Jika Anda menerima error, lihat Langkah 5 untuk menemukan project ID yang Anda gunakan selama lab. Ganti dengan perintah pada petunjuk pertama. Misalnya, jika project ID Anda adalah lab-example-project, perintahnya adalah:
    gcloud projects delete lab-project-id-example --quiet
    

13. Selamat

Di lab ini, Anda telah membuat aplikasi AI Generatif yang menggunakan model Gemini untuk membuat prediksi. Dan menginstrumentasikan aplikasi dengan kemampuan pemantauan dan logging penting. Anda telah men-deploy aplikasi dan perubahan dari kode sumber ke Cloud Run. Kemudian, Anda dapat menggunakan produk Google Cloud Observability untuk melacak performa aplikasi, sehingga Anda dapat memastikan keandalan aplikasi.

Jika Anda tertarik untuk disertakan dalam studi riset pengalaman pengguna (UX) untuk meningkatkan kualitas produk yang Anda gunakan hari ini, daftar di sini.

Berikut beberapa opsi untuk melanjutkan pembelajaran Anda: