// Copyright 2020 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.

// Protos for logging firebase performance monitoring metrics collected by the
// Firebase performance sdk and transmitted to the backend using clearcut.

syntax = "proto2";

package firebase.perf.v1;

option java_multiple_files = true;
option java_outer_classname = "FirebasePerfMetricProto";
option java_package = "com.google.firebase.perf.v1";

// Firebase Perf Reporting Message
option objc_class_prefix = "FPRMSG";

// Single unit of performance data collected from firebase integrated 3P apps by
// the firebase performance sdk. This will be an an extension to
// GWSLogEntryProto and will correspond to one record in the RecordIO logs
// generated by clearcut. Every firebase performance related event logged to
// clearcut/Firelog by the sdk will encapsulate one instance of this object.
//
// Next tag: 6
message PerfMetric {

  // Additional metadata about an application and its state (including state of
  // the device at runtime) that is not provided by clearcut.
  optional ApplicationInfo application_info = 1;

  // A metric which represents the performance statistics collected within an
  // instrumented trace.
  optional TraceMetric trace_metric = 2;

  // A metric which represents the network latency, bandwidth and network
  // connection info about a network request captured by the firebase sdk.
  optional NetworkRequestMetric network_request_metric = 3;

  // A metric which represents session gauges, such as cpu, memory, battery,
  // within a session.
  optional GaugeMetric gauge_metric = 4;

  // A metric which represents the transport related information.
  // When transport_info field is empty, it means the message is from clearcut.
  optional TransportInfo transport_info = 5;
}

// Metric which represents everything collected in the span of a trace. A trace
// may be further divided into subtraces.
// The trace can either be a default out of the box trace which is a
// part of the default instrumentation provided by the firebase performance sdk
// or a custom trace instrumented by the app developer using the sdk apis.
//
// Next tag: 10
message TraceMetric {
  // The name of the trace. This could either be a user defined name for the
  // developer instrumented custom traces or a default for traces automatically
  // instrumented by the Firebase Performance SDK. The max length of 64
  // characters will be enforced by the sdk.
  optional string name = 1;  // required.

  // If true, then this is considered to be a trace automatically instrumented
  // by the performance sdk. Otherwise, it is considered to be a custom trace
  // instrumented by the developer using firebase perf sdk apis.
  optional bool is_auto = 2;

  // The timestamp in microseconds since epoch when the trace was started. This
  // time is recorded using the device clock.
  optional int64 client_start_time_us = 4;  // required.

  // The duration of the trace in microseconds.
  optional int64 duration_us = 5;  // required.

  // A map of custom or default counter names to values.
  map<string, int64> counters = 6;

  // The metrics for subtraces within the trace.

  // The following restrictions are currently enforced by the sdk on subtraces:
  // Subtraces should only have 1 level of nesting.
  // Subtraces should be non overlapping.
  // Subtraces should be continuous, i.e no gaps between consecutive subtraces.
  repeated TraceMetric subtraces = 7;

  // A map of trace-level custom attribute names to values.
  map<string, string> custom_attributes = 8;

  // Sessions across which the trace spanned. A session lasts from one
  // change in the app state (foreground/background) to the next. Basically
  // every foreground and background session gets it's own session id. A trace
  // may span across multiple such sessions. So we need a list to identify which
  // sessions it spanned across.
  repeated PerfSession perf_sessions = 9;
}

// Metric which represents the latency, bandwidth consumption and other details
// about a network request captured by the firebase sdk.
//
// Next tag: 14
message NetworkRequestMetric {
  // The parameterless url to which the network request was made. The sdk will
  // redact the unnecessary components of the URL and only log the components
  // which are useful. For a url of the form
  // scheme://host[:port]/path[?params][#fragment], the sdk should only log
  // scheme://host[:port]/path
  // Example:
  // Captured Url: https://wwww.google.com/maps/cities#seattle?id=123
  // Logged Url: https://wwww.google.com/maps/cities
  optional string url = 1;  // required.

  // Supported HTTP methods for aggregating network requests. All network
  // requests that can not be classified into the 9 methods below should be set
  // to HTTP_METHOD_UNKNOWN.
  enum HttpMethod {
    HTTP_METHOD_UNKNOWN = 0;
    GET = 1;
    PUT = 2;
    POST = 3;
    DELETE = 4;
    HEAD = 5;
    PATCH = 6;
    OPTIONS = 7;
    TRACE = 8;
    CONNECT = 9;
  }

  // The HTTP verb for the network request. Common values include GET,
  // PUT, POST and DELETE
  optional HttpMethod http_method = 2;  // required.

  // The size of the payload in the request.
  optional int64 request_payload_bytes = 3;

  // The size of the payload in the response.
  optional int64 response_payload_bytes = 4;

  // Info about the type of client error during network call.
  enum NetworkClientErrorReason {
    // Unspecified Network Client Error Reason.
    NETWORK_CLIENT_ERROR_REASON_UNKNOWN = 0;
    // No attempt made to classify the error.
    GENERIC_CLIENT_ERROR = 1;
    // Add the specific client error types below.
  }

  // The client error received from the networking library.
  // Do not record a client error if we have HTTP response code available.
  optional NetworkClientErrorReason network_client_error_reason = 11;

  // The Http response code received from the server.
  optional int32 http_response_code = 5;  // required.

  // The value of the content type header in the response.
  optional string response_content_type = 6;

  // The timestamp in microseconds since epoch when the network request was
  // initiated. This time is recorded using the device clock.
  optional int64 client_start_time_us = 7;  // required.

  // The time in microseconds since the start of the network request and the
  // upload of the last request byte.
  optional int64 time_to_request_completed_us = 8;

  // The time in microseconds between the start of the network request and the
  // receipt of the first byte of the response headers.
  optional int64 time_to_response_initiated_us = 9;

  // The time in microseconds between the start of the network request and the
  // receipt of the last response byte.
  optional int64 time_to_response_completed_us = 10;  // required.

  // A map of network-level custom attribute names to values.
  map<string, string> custom_attributes = 12;

  // Sessions across which the network request spanned. A session lasts
  // from one change in the app state (foreground/background) to the next.
  // Basically every foreground and background session gets it's own session id.
  // A network request may span across multiple such sessions. So we need a list
  // to identify which sessions it spanned across.
  repeated PerfSession perf_sessions = 13;
}

// Metadata about a session and the amount of detail information it contains.
message PerfSession {
  // The id of a session.
  optional string session_id = 1;

  // The level of amount of detailed information that this session captures.
  repeated SessionVerbosity session_verbosity = 2;
}

// Metric which represents gauges collected during the span of a session,
// including cpu, memory, battery, etc.
// The gauges will be collected by our own sdk and be purely numeric readings,
// user cannot pass any information here, so cannot contain PIIs.
//
// Next tag: 6
message GaugeMetric {
  // Identifier of the session in which this gauge reading takes place.
  // A session_id is specific to a device instance, and is used to tie gauge
  // metrics to other peer traces and network requests that occurs during
  // the session.
  optional string session_id = 1;

  // Metadata of gauge metrics whose value stay constant throughout the session.
  optional GaugeMetadata gauge_metadata = 3;

  // List of cpu gauge readings recorded in the session.
  repeated CpuMetricReading cpu_metric_readings = 2;

  // List of Android memory readings recorded, absent for iOS apps.
  repeated AndroidMemoryReading android_memory_readings = 4;

  // List of iOS memory readings recorded, absent for Android apps.
  repeated IosMemoryReading ios_memory_readings = 5;
}

// One reading of cpu gauge metric.
//
// Next tag: 4
message CpuMetricReading {
  // The timestamp in microseconds since epoch when this snapshot took place.
  // This time is recorded using the device clock.
  optional int64 client_time_us = 1;
  // The total user cpu time since process started in microseconds.
  optional int64 user_time_us = 2;
  // The total system cpu time since process started in microseconds.
  optional int64 system_time_us = 3;
}

// One reading of iOS memory gauge metric.
//
// Next tag: 4
message IosMemoryReading {
  // The timestamp in microseconds since epoch when this snapshot took place.
  // This time is recorded using the device clock.
  optional int64 client_time_us = 1;

  // The amount of heap memory that the app is using, in kilobytes.
  optional int32 used_app_heap_memory_kb = 2;

  // The amount of heap memory that is free for the app to use, in kilobytes.
  optional int32 free_app_heap_memory_kb = 3;
}

// One reading of Android memory gauge metric.
// Note that this is cheap-to-capture memory reading, which is different from
// application's summary of memory usage (expensive to capture). Summary of
// memory usage will be captured at a much lower frequency in a different proto.
//
// Next tag: 3
message AndroidMemoryReading {
  // The timestamp in microseconds since epoch when this snapshot took place.
  // This time is recorded using the device clock.
  optional int64 client_time_us = 1;

  // The amount of java heap memory that the app is using, in kilobytes.
  optional int32 used_app_java_heap_memory_kb = 2;
}

// Metadata about gauges of a session.
// These are the gauge values that stay constant throughout the entire session.
// Examples include maxAppJavaHeapMemory (max memory allowed for the app) and
// cpuFrequency (frequency of cpu of the device that the app is running on).
// As long as one GaugeMetadata is sent for a session, these metadata will be
// available for all elements of the session. If multiple GaugeMetadata are sent
// for the same session, they are expected to be identical.
//
// Next tag: 7
message GaugeMetadata {
  // The process in which Firebase instance is initialized and collecting data.
  // Fireperf sdk collects information in the context of a process (instead of
  // the whole app). The process name helps developer identifies which process
  // are the gauge data coming from.
  optional string process_name = 1;

  // Clock rate of the cpu of the device, in kHz.
  optional int32 cpu_clock_rate_khz = 2;

  // The number of cpu cores that the device has.
  optional int32 cpu_processor_count = 6;

  // Size of RAM of the device, in kilobytes.
  optional int32 device_ram_size_kb = 3;

  // Maximum amount of memory the app can use before an OutOfMemoryException
  // is triggered, in kilobytes.
  // Only present for Android apps.
  optional int32 max_app_java_heap_memory_kb = 4;

  // The maximum amount of memory the app is encouraged to use to be properly
  // respectful of the limits of the client device.
  // Only present for Android apps.
  optional int32 max_encouraged_app_java_heap_memory_kb = 5;
}

// Additional metadata about an application and its state (including state of
// the device at runtime) that is not provided by clearcut.
//
// Next tag: 8
message ApplicationInfo {
  // Identifier for the application that has been registered with firebase.
  // Contains pantheon project number, platform and the hash of the (package
  // name or bundle id) fields in hex.
  // [Version]:[Project Number]:[Platform]:[Hash(package_name/bundle_id)]
  // The app id contains Pantheon project number which is a GAIA ID that
  // identifies a particular organization or a customer.
  optional string google_app_id = 1;  // required.

  // The App Instance Id which is used to compute the distinct users for which
  // the metrics are recorded.
  optional string app_instance_id = 2;  // required.

  // One of android_app_info, ios_app_info, and web_app_info is required.

  // Additional information specific to an android app.
  optional AndroidApplicationInfo android_app_info = 3;

  // Additional information specific to an ios app.
  optional IosApplicationInfo ios_app_info = 4;

  // Additional information specific to a web app.
  optional WebApplicationInfo web_app_info = 7;

  // State of the application process during metric collection.
  optional ApplicationProcessState application_process_state = 5;  // required.

  // A map of global-level custom attribute names to values.
  map<string, string> custom_attributes = 6;
}

// Additional metadata about a web application that is not provided by
// clearcut.
//
// Next tag: 6
message WebApplicationInfo {
  // The sdk version of the firebase perf web sdk.
  optional string sdk_version = 1;

  // The url of the web page from which this event occurs.
  optional string page_url = 2;

  // Service worker status of the web page.
  optional ServiceWorkerStatus service_worker_status = 3;

  // Visibility state of the web page.
  optional VisibilityState visibility_state = 4;

  // Effective connection type of a web page.
  optional EffectiveConnectionType effective_connection_type = 5;
}

// Additional metadata about an android application that is not provided by
// clearcut.
//
// Next tag: 4
message AndroidApplicationInfo {
  // The package name of the android application.
  // e.g com.google.android.apps.maps
  optional string package_name = 1;  // required.

  // The sdk version of the firebase perf android sdk.
  optional string sdk_version = 2;  // required.

  // The versionName of the android application as shown on the play store.
  // Clearcut logs the versionCode in the GWSLogEntryProto field:
  // PlayExtension.client_info.android_client_info.application_build
  // This field is necessary till clearcut supports logging version_name by
  // default: b/32584283
  optional string version_name = 3;
}

// To describe the network connectivity of the client.
// Copied from android/play/playlog/proto/clientanalytics.proto
// Next tag: 3
message NetworkConnectionInfo {
  enum NetworkType {
    NONE = -1;
    MOBILE = 0;
    WIFI = 1;
    MOBILE_MMS = 2;
    MOBILE_SUPL = 3;
    MOBILE_DUN = 4;
    MOBILE_HIPRI = 5;
    WIMAX = 6;
    BLUETOOTH = 7;
    DUMMY = 8;
    ETHERNET = 9;
    MOBILE_FOTA = 10;
    MOBILE_IMS = 11;
    MOBILE_CBS = 12;
    WIFI_P2P = 13;
    MOBILE_IA = 14;
    MOBILE_EMERGENCY = 15;
    PROXY = 16;
    VPN = 17;
  }

  enum MobileSubtype {
    UNKNOWN_MOBILE_SUBTYPE = 0;
    GPRS = 1;
    EDGE = 2;
    UMTS = 3;
    CDMA = 4;
    EVDO_0 = 5;
    EVDO_A = 6;
    RTT = 7;
    HSDPA = 8;
    HSUPA = 9;
    HSPA = 10;
    IDEN = 11;
    EVDO_B = 12;
    LTE = 13;
    EHRPD = 14;
    HSPAP = 15;
    GSM = 16;
    TD_SCDMA = 17;
    IWLAN = 18;
    LTE_CA = 19;

    // COMBINED has value -1 in NetworkIdentity.java, but is given the value
    // 100 here to save (disk) space. The value -1 takes up the full 10 bytes in
    // a varint for enums, but the value 100 only takes up 1 byte.
    COMBINED = 100;
  }

  // The current network connectivity type when the event was logged in the
  // client
  optional NetworkType network_type = 1 [default = NONE];

  // The current mobile connectivity subtype when the event was logged in the
  // client
  optional MobileSubtype mobile_subtype = 2 [default = UNKNOWN_MOBILE_SUBTYPE];
}

// Additional metadata about an ios application that is not provided by
// clearcut.
//
// Next tag: 6
message IosApplicationInfo {
  reserved 1;

  // The version of the firebase perf ios sdk.
  optional string sdk_version = 2;  // required.

  // The CFBundleShortVersionString of the ios application bundle as shown on
  // the ios app store.
  // Clearcut logs the CFBundleVersion in the GWSLogEntryProto field:
  // PlayExtension.client_info.ios_client_info.application_build
  optional string bundle_short_version = 3;  // required.

  // The mobile country code / mobile network code (MCC/MNC) of the device's
  // SIM/home network (not the device's active network)
  // e.g., 310004 for Verizon USA.
  // This field should eventually move to PlaylogIosClientInfo. b/35763500
  optional string mcc_mnc = 4;

  // The network connectivity of the client when the fetch was done.
  optional NetworkConnectionInfo network_connection_info = 5;  // required.
}

// Transport related metadata info.
// Next tag: 2
message TransportInfo {
  // Dispatch destination for the event.
  enum DispatchDestination {
    SOURCE_UNKNOWN = 0;  // Reserved
    FL_LEGACY_V1 = 1;    // Firelog legacy endpoint
  }

  // Destination to which the events are sent.
  optional DispatchDestination dispatch_destination = 1;
}

// Metadata about the state of application process during metrics collection.
//
enum ApplicationProcessState {
  // Unspecified application process state.
  APPLICATION_PROCESS_STATE_UNKNOWN = 0;
  // Application process was in foreground
  FOREGROUND = 1;
  // Application process was in background
  BACKGROUND = 2;
  // Application process was both in foreground and background for the duration
  // of metrics collection.
  FOREGROUND_BACKGROUND = 3;
}

// The level of detailed information that is captured in a Perf Session, known
// as a session's verbosity. For different session we collect different levels
// of detailed information (or none at all) to avoid penalizing the same device
// constantly.
enum SessionVerbosity {
  // Session doesn't have detailed information.
  SESSION_VERBOSITY_NONE = 0;
  // Session has gauges and system events information.
  GAUGES_AND_SYSTEM_EVENTS = 1;
}

// Visibility state for a web page.
enum VisibilityState {
  // Unspecified visibility state.
  VISIBILITY_STATE_UNKNOWN = 0;
  // The page is at least partially visible. In practice this means the page
  // is in the foreground tab of a non-minimized window.
  VISIBLE = 1;
  // The page's content is not visible to the user.
  HIDDEN = 2;
  // The page's content is being prerendered and is not visible to the user.
  PRERENDER = 3;
  // The page is in the process of being unloaded from memory.
  UNLOADED = 4;
}

// Service worker status for a web page.
enum ServiceWorkerStatus {
  // Unspecified service worker status.
  SERVICE_WORKER_STATUS_UNKNOWN = 0;
  // Service worker not supported by the browser.
  UNSUPPORTED = 1;
  // Service worker controlled page.
  CONTROLLED = 2;
  // Page not controlled by a service worker.
  UNCONTROLLED = 3;
}

// Effective connection type for a web application, defined from
// https://wicg.github.io/netinfo/#effective-connection-types
enum EffectiveConnectionType {
  EFFECTIVE_CONNECTION_TYPE_UNKNOWN = 0;
  EFFECTIVE_CONNECTION_TYPE_SLOW_2G = 1;  // Maximum downlink speed 50kbs
  EFFECTIVE_CONNECTION_TYPE_2G = 2;       // Maximum downlink speed 70kbs
  EFFECTIVE_CONNECTION_TYPE_3G = 3;       // Maximum downlink speed 700kbs
  EFFECTIVE_CONNECTION_TYPE_4G = 4;       // Maximum downlink speed Infinity
}
