Scarica i dati del profilo

Questo documento descrive come scaricare i dati del profilo sul sistema locale e come recuperarli tramite programmazione utilizzando un'applicazione Go.

Scaricare i profili utilizzando la console Google Cloud

Per scaricare il profilo visualizzato nel grafico a forma di fiamma, fai clic su Scarica .

Profiler utilizza la seguente convenzione di denominazione per il file scaricato:

profiler_[SERVICE_NAME]_[PROFILE_TYPE]_[FROM_DATE]_[TO_DATE]_[ZONE]_[VERSION].pb.gz

In questa espressione:

  • SERVICE_NAME contiene la selezione del servizio
  • PROFILE_TYPE contiene la selezione del Tipo di profilo
  • FROM_DATE e TO_DATE contengono le specifiche dell'intervallo di tempo
  • ZONE contiene la selezione della zona
  • VERSION contiene la selezione della versione

Esempio: profiler_docdemo-service_HEAP_2018-04-22T20_25_31Z_2018-05-22T20_25_31Z_us-east1-c.pb.gz

Scaricare i profili in modo programmatico

Per recuperare i dati del profilo, utilizza il metodo dell'API ListProfiles. Il seguente programma Go di esempio mostra l'utilizzo di questa API.

Il programma di esempio crea una cartella nella directory da cui viene eseguito e genera un insieme di file pprof numerati. Ogni file ha una convenzione di denominazione simile a profile000042.pb.gz. Ogni directory contiene i dati del profilo e un file di metadati (metadata.csv), che contiene informazioni sui file scaricati.


// Sample export shows how ListProfiles API can be used to download
// existing pprof profiles for a given project from GCP.
package main

import (
	"bytes"
	"context"
	"encoding/csv"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"time"

	cloudprofiler "cloud.google.com/go/cloudprofiler/apiv2"
	pb "cloud.google.com/go/cloudprofiler/apiv2/cloudprofilerpb"
	"google.golang.org/api/iterator"
)

var project = flag.String("project", "", "GCP project ID from which profiles should be fetched")
var pageSize = flag.Int("page_size", 100, "Number of profiles fetched per page. Maximum 1000.")
var pageToken = flag.String("page_token", "", "PageToken from a previous ListProfiles call. If empty, the listing will start from the begnning. Invalid page tokens result in error.")
var maxProfiles = flag.Int("max_profiles", 1000, "Maximum number of profiles to fetch across all pages. If this is <= 0, will fetch all available profiles")

const ProfilesDownloadedSuccessfully = "Read max allowed profiles"

// This function reads profiles for a given project and stores them into locally created files.
// The profile metadata gets stored into a 'metdata.csv' file, while the individual pprof files
// are created per profile.
func downloadProfiles(ctx context.Context, w io.Writer, project, pageToken string, pageSize, maxProfiles int) error {
	client, err := cloudprofiler.NewExportClient(ctx)
	if err != nil {
		return err
	}
	defer client.Close()
	log.Printf("Attempting to fetch %v profiles with a pageSize of %v for %v\n", maxProfiles, pageSize, project)

	// Initial request for the ListProfiles API
	request := &pb.ListProfilesRequest{
		Parent:    fmt.Sprintf("projects/%s", project),
		PageSize:  int32(pageSize),
		PageToken: pageToken,
	}

	// create a folder for storing profiles & metadata
	profilesDirName := fmt.Sprintf("profiles_%v", time.Now().Unix())
	if err := os.Mkdir(profilesDirName, 0750); err != nil {
		log.Fatal(err)
	}
	// create a file for storing profile metadata
	metadata, err := os.Create(fmt.Sprintf("%s/metadata.csv", profilesDirName))
	if err != nil {
		return err
	}
	defer metadata.Close()

	writer := csv.NewWriter(metadata)
	defer writer.Flush()

	writer.Write([]string{"File", "Name", "ProfileType", "Target", "Duration", "Labels"})

	profileCount := 0
	// Keep calling ListProfiles API till all profile pages are fetched or max pages reached
	profilesIterator := client.ListProfiles(ctx, request)
	for {
		// Read individual profile - the client will automatically make API calls to fetch next pages
		profile, err := profilesIterator.Next()

		if err == iterator.Done {
			log.Println("Read all available profiles")
			break
		}
		if err != nil {
			return fmt.Errorf("error reading profile from response: %w", err)
		}
		profileCount++

		filename := fmt.Sprintf("%s/profile%06d.pb.gz", profilesDirName, profileCount)
		err = os.WriteFile(filename, profile.ProfileBytes, 0640)

		if err != nil {
			return fmt.Errorf("unable to write file %s: %w", filename, err)
		}
		fmt.Fprintf(w, "deployment target: %v\n", profile.Deployment.Labels)

		labelBytes, err := json.Marshal(profile.Labels)
		if err != nil {
			return err
		}

		err = writer.Write([]string{filename, profile.Name, profile.Deployment.Target, profile.Duration.String(), string(labelBytes)})
		if err != nil {
			return err
		}

		if maxProfiles > 0 && profileCount >= maxProfiles {
			fmt.Fprintf(w, "result: %v", ProfilesDownloadedSuccessfully)
			break
		}

		if profilesIterator.PageInfo().Remaining() == 0 {
			// This signifies that the client will make a new API call internally
			log.Printf("next page token: %v\n", profilesIterator.PageInfo().Token)
		}
	}
	return nil
}

func main() {
	flag.Parse()
	// validate project ID
	if *project == "" {
		log.Fatalf("No project ID provided, please provide the GCP project ID via '-project' flag")
	}
	var writer bytes.Buffer
	if err := downloadProfiles(context.Background(), &writer, *project, *pageToken, *pageSize, *maxProfiles); err != nil {
		log.Fatal(err)
	}
	log.Println("Finished reading all profiles")
}

Il programma di esempio accetta i seguenti argomenti della riga di comando:

  • project: il progetto da cui vengono recuperati i profili. Obbligatorio.
  • page_size: il numero massimo di profili recuperati per chiamata API. Il valore massimo di page_size è 1000. Se non specificato, questo campo viene impostato su 100.
  • page_token: un token di stringa generato da un'esecuzione precedente del programma per riprendere i download. Facoltativo.
  • max_profiles: il numero massimo di profili da recuperare. Se viene fornito un numero intero non positivo, il programma tenta di recuperare tutti i profili.
    Facoltativo.

Esegui l'applicazione di esempio

Per eseguire l'applicazione di esempio:

  1. Clona il repository:

    git clone https://github.com/GoogleCloudPlatform/golang-samples.git
    
  2. Passa alla directory che contiene il programma di esempio:

    cd golang-samples/profiler/export
    
  3. Esegui il programma dopo aver sostituito YOUR_GCP_PROJECT con l'ID del tuo progetto Google Cloud:

    go run main.go -project YOUR_GCP_PROJECT -page_size 1000 -max_profiles 10000
    

Il completamento del programma potrebbe richiedere molto tempo. Il programma genera un token per la pagina successiva dopo aver recuperato la pagina corrente. Puoi utilizzare il token per riprendere la procedura se il programma viene interrotto.

Visualizzare i profili scaricati

Per leggere un file scaricato, scritto nel formato serializzato del buffer di protocollo, utilizza lo strumento open source pprof.