// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package google.devtools.cloudprofiler.v2;

import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/timestamp.proto";

option csharp_namespace = "Google.Cloud.Profiler.V2";
option go_package = "cloud.google.com/go/cloudprofiler/apiv2/cloudprofilerpb;cloudprofilerpb";
option java_multiple_files = true;
option java_outer_classname = "ProfilerProto";
option java_package = "com.google.devtools.cloudprofiler.v2";
option php_namespace = "Google\\Cloud\\Profiler\\V2";
option ruby_package = "Google::Cloud::Profiler::V2";

// Manage the collection of continuous profiling data provided by profiling
// agents running in the cloud or by an offline provider of profiling data.
//
// __The APIs listed in this service are intended for use within our profiler
// agents only.__
service ProfilerService {
  option (google.api.default_host) = "cloudprofiler.googleapis.com";
  option (google.api.oauth_scopes) =
      "https://www.googleapis.com/auth/cloud-platform,"
      "https://www.googleapis.com/auth/monitoring,"
      "https://www.googleapis.com/auth/monitoring.write";

  // CreateProfile creates a new profile resource in the online mode.
  //
  // _Direct use of this API is discouraged, please use a [supported
  // profiler
  // agent](https://cloud.google.com/profiler/docs/about-profiler#profiling_agent)
  // instead for profile collection._
  //
  // The server ensures that the new profiles are created at a constant rate per
  // deployment, so the creation request may hang for some time until the next
  // profile session is available.
  //
  // The request may fail with ABORTED error if the creation is not available
  // within ~1m, the response will indicate the duration of the backoff the
  // client should take before attempting creating a profile again. The backoff
  // duration is returned in google.rpc.RetryInfo extension on the response
  // status. To a gRPC client, the extension will be return as a
  // binary-serialized proto in the trailing metadata item named
  // "google.rpc.retryinfo-bin".
  //
  rpc CreateProfile(CreateProfileRequest) returns (Profile) {
    option (google.api.http) = {
      post: "/v2/{parent=projects/*}/profiles"
      body: "*"
    };
  }

  // CreateOfflineProfile creates a new profile resource in the offline
  // mode. The client provides the profile to create along with the profile
  // bytes, the server records it.
  //
  // _Direct use of this API is discouraged, please use a [supported
  // profiler
  // agent](https://cloud.google.com/profiler/docs/about-profiler#profiling_agent)
  // instead for profile collection._
  rpc CreateOfflineProfile(CreateOfflineProfileRequest) returns (Profile) {
    option (google.api.http) = {
      post: "/v2/{parent=projects/*}/profiles:createOffline"
      body: "profile"
    };
    option (google.api.method_signature) = "parent,profile";
  }

  // UpdateProfile updates the profile bytes and labels on the profile resource
  // created in the online mode. Updating the bytes for profiles created in the
  // offline mode is currently not supported: the profile content must be
  // provided at the time of the profile creation.
  //
  // _Direct use of this API is discouraged, please use a [supported
  // profiler
  // agent](https://cloud.google.com/profiler/docs/about-profiler#profiling_agent)
  // instead for profile collection._
  rpc UpdateProfile(UpdateProfileRequest) returns (Profile) {
    option (google.api.http) = {
      patch: "/v2/{profile.name=projects/*/profiles/*}"
      body: "profile"
    };
    option (google.api.method_signature) = "profile,update_mask";
  }
}

// Service allows existing Cloud Profiler customers to export their profile data
// out of Google Cloud.
service ExportService {
  option (google.api.default_host) = "cloudprofiler.googleapis.com";
  option (google.api.oauth_scopes) =
      "https://www.googleapis.com/auth/cloud-platform,"
      "https://www.googleapis.com/auth/monitoring,"
      "https://www.googleapis.com/auth/monitoring.write";

  // Lists profiles which have been collected so far and for which the caller
  // has permission to view.
  rpc ListProfiles(ListProfilesRequest) returns (ListProfilesResponse) {
    option (google.api.http) = {
      get: "/v2/{parent=projects/*}/profiles"
    };
    option (google.api.method_signature) = "parent";
  }
}

// CreateProfileRequest describes a profile resource online creation request.
// The deployment field must be populated. The profile_type specifies the list
// of profile types supported by the agent. The creation call will hang until a
// profile of one of these types needs to be collected.
//
message CreateProfileRequest {
  // Parent project to create the profile in.
  string parent = 4 [(google.api.resource_reference) = {
    type: "cloudresourcemanager.googleapis.com/Project"
  }];

  // Deployment details.
  Deployment deployment = 1;

  // One or more profile types that the agent is capable of providing.
  repeated ProfileType profile_type = 2;
}

// CreateOfflineProfileRequest describes a profile resource offline creation
// request.
message CreateOfflineProfileRequest {
  // Parent project to create the profile in.
  string parent = 1 [(google.api.resource_reference) = {
    type: "cloudresourcemanager.googleapis.com/Project"
  }];

  // Contents of the profile to create.
  Profile profile = 2;
}

// UpdateProfileRequest contains the profile to update.
message UpdateProfileRequest {
  // Profile to update.
  Profile profile = 1;

  // Field mask used to specify the fields to be overwritten. Currently only
  // profile_bytes and labels fields are supported by UpdateProfile, so only
  // those fields can be specified in the mask. When no mask is provided, all
  // fields are overwritten.
  google.protobuf.FieldMask update_mask = 2;
}

// Profile resource.
message Profile {
  option (google.api.resource) = {
    type: "cloudprofiler.googleapis.com/Profile"
    pattern: "projects/{project}/profiles/{profile}"
  };

  // Output only. Opaque, server-assigned, unique ID for this profile.
  string name = 1 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Type of profile.
  // For offline mode, this must be specified when creating the profile. For
  // online mode it is assigned and returned by the server.
  ProfileType profile_type = 2;

  // Deployment this profile corresponds to.
  Deployment deployment = 3;

  // Duration of the profiling session.
  // Input (for the offline mode) or output (for the online mode).
  // The field represents requested profiling duration. It may slightly differ
  // from the effective profiling duration, which is recorded in the profile
  // data, in case the profiling can't be stopped immediately (e.g. in case
  // stopping the profiling is handled asynchronously).
  google.protobuf.Duration duration = 4;

  // Input only. Profile bytes, as a gzip compressed serialized proto, the
  // format is https://github.com/google/pprof/blob/master/proto/profile.proto.
  bytes profile_bytes = 5 [(google.api.field_behavior) = INPUT_ONLY];

  // Input only. Labels associated to this specific profile. These labels will
  // get merged with the deployment labels for the final data set. See
  // documentation on deployment labels for validation rules and limits.
  map<string, string> labels = 6 [(google.api.field_behavior) = INPUT_ONLY];

  // Output only. Start time for the profile.
  // This output is only present in response from the ListProfiles method.
  google.protobuf.Timestamp start_time = 7
      [(google.api.field_behavior) = OUTPUT_ONLY];
}

// Deployment contains the deployment identification information.
message Deployment {
  // Project ID is the ID of a cloud project.
  // Validation regex: `^[a-z][-a-z0-9:.]{4,61}[a-z0-9]$`.
  string project_id = 1;

  // Target is the service name used to group related deployments:
  // * Service name for App Engine Flex / Standard.
  // * Cluster and container name for GKE.
  // * User-specified string for direct Compute Engine profiling (e.g. Java).
  // * Job name for Dataflow.
  // Validation regex: `^[a-z0-9]([-a-z0-9_.]{0,253}[a-z0-9])?$`.
  string target = 2;

  // Labels identify the deployment within the user universe and same target.
  // Validation regex for label names: `^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$`.
  // Value for an individual label must be <= 512 bytes, the total
  // size of all label names and values must be <= 1024 bytes.
  //
  // Label named "language" can be used to record the programming language of
  // the profiled deployment. The standard choices for the value include "java",
  // "go", "python", "ruby", "nodejs", "php", "dotnet".
  //
  // For deployments running on Google Cloud Platform, "zone" or "region" label
  // should be present describing the deployment location. An example of a zone
  // is "us-central1-a", an example of a region is "us-central1" or
  // "us-central".
  map<string, string> labels = 3;
}

// ProfileType is type of profiling data.
// NOTE: the enumeration member names are used (in lowercase) as unique string
// identifiers of profile types, so they must not be renamed.
enum ProfileType {
  // Unspecified profile type.
  PROFILE_TYPE_UNSPECIFIED = 0;

  // Thread CPU time sampling.
  CPU = 1;

  // Wallclock time sampling. More expensive as stops all threads.
  WALL = 2;

  // In-use heap profile. Represents a snapshot of the allocations that are
  // live at the time of the profiling.
  HEAP = 3;

  // Single-shot collection of all thread stacks.
  THREADS = 4;

  // Synchronization contention profile.
  CONTENTION = 5;

  // Peak heap profile.
  PEAK_HEAP = 6;

  // Heap allocation profile. It represents the aggregation of all allocations
  // made over the duration of the profile. All allocations are included,
  // including those that might have been freed by the end of the profiling
  // interval. The profile is in particular useful for garbage collecting
  // languages to understand which parts of the code create most of the garbage
  // collection pressure to see if those can be optimized.
  HEAP_ALLOC = 7;
}

// ListProfilesRequest contains request parameters for listing profiles for
// deployments in projects which the user has permissions to view.
message ListProfilesRequest {
  // Required. The parent, which owns this collection of profiles.
  // Format: projects/{user_project_id}
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "cloudresourcemanager.googleapis.com/Project"
    }
  ];

  // The maximum number of items to return.
  // Default page_size is 1000.
  // Max limit is 1000.
  int32 page_size = 2;

  // The token to continue pagination and get profiles from a particular page.
  // When paginating, all other parameters provided to `ListProfiles` must match
  // the call that provided the page token.
  string page_token = 3;
}

// ListProfileResponse contains the list of collected profiles for deployments
// in projects which the user has permissions to view.
message ListProfilesResponse {
  // List of profiles fetched.
  repeated Profile profiles = 1;

  // Token to receive the next page of results.
  // This field maybe empty if there are no more profiles to fetch.
  string next_page_token = 2;

  // Number of profiles that were skipped in the current page since they were
  // not able to be fetched successfully. This should typically be zero. A
  // non-zero value may indicate a transient failure, in which case if the
  // number is too high for your use case, the call may be retried.
  int32 skipped_profiles = 3;
}
