// Copyright 2017, OpenCensus Authors
//
// 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 opencensus.proto.trace.v1;

import "opencensus/proto/resource/v1/resource.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";

option java_multiple_files = true;
option java_package = "io.opencensus.proto.trace.v1";
option java_outer_classname = "TraceProto";

option go_package = "github.com/census-instrumentation/opencensus-proto/gen-go/trace/v1";

// A span represents a single operation within a trace. Spans can be
// nested to form a trace tree. Spans may also be linked to other spans
// from the same or different trace. And form graphs. Often, a trace
// contains a root span that describes the end-to-end latency, and one
// or more subspans for its sub-operations. A trace can also contain
// multiple root spans, or none at all. Spans do not need to be
// contiguous - there may be gaps or overlaps between spans in a trace.
//
// The next id is 17.
// TODO(bdrutu): Add an example.
message Span {
  // A unique identifier for a trace. All spans from the same trace share
  // the same `trace_id`. The ID is a 16-byte array. An ID with all zeroes
  // is considered invalid.
  //
  // This field is semantically required. Receiver should generate new
  // random trace_id if empty or invalid trace_id was received.
  //
  // This field is required.
  bytes trace_id = 1;

  // A unique identifier for a span within a trace, assigned when the span
  // is created. The ID is an 8-byte array. An ID with all zeroes is considered
  // invalid.
  //
  // This field is semantically required. Receiver should generate new
  // random span_id if empty or invalid span_id was received.
  //
  // This field is required.
  bytes span_id = 2;

  // This field conveys information about request position in multiple distributed tracing graphs.
  // It is a list of Tracestate.Entry with a maximum of 32 members in the list.
  //
  // See the https://github.com/w3c/distributed-tracing for more details about this field.
  message Tracestate {
    message Entry {
      // The key must begin with a lowercase letter, and can only contain
      // lowercase letters 'a'-'z', digits '0'-'9', underscores '_', dashes
      // '-', asterisks '*', and forward slashes '/'.
      string key = 1;

      // The value is opaque string up to 256 characters printable ASCII
      // RFC0020 characters (i.e., the range 0x20 to 0x7E) except ',' and '='.
      // Note that this also excludes tabs, newlines, carriage returns, etc.
      string value = 2;
    }

    // A list of entries that represent the Tracestate.
    repeated Entry entries = 1;
  }

  // The Tracestate on the span.
  Tracestate tracestate = 15;

  // The `span_id` of this span's parent span. If this is a root span, then this
  // field must be empty. The ID is an 8-byte array.
  bytes parent_span_id = 3;

  // A description of the span's operation.
  //
  // For example, the name can be a qualified method name or a file name
  // and a line number where the operation is called. A best practice is to use
  // the same display name at the same call point in an application.
  // This makes it easier to correlate spans in different traces.
  //
  // This field is semantically required to be set to non-empty string.
  // When null or empty string received - receiver may use string "name"
  // as a replacement. There might be smarted algorithms implemented by
  // receiver to fix the empty span name.
  //
  // This field is required.
  TruncatableString name = 4;

  // Type of span. Can be used to specify additional relationships between spans
  // in addition to a parent/child relationship.
  enum SpanKind {
    // Unspecified.
    SPAN_KIND_UNSPECIFIED = 0;

    // Indicates that the span covers server-side handling of an RPC or other
    // remote network request.
    SERVER = 1;

    // Indicates that the span covers the client-side wrapper around an RPC or
    // other remote request.
    CLIENT = 2;
  }

  // Distinguishes between spans generated in a particular context. For example,
  // two spans with the same name may be distinguished using `CLIENT` (caller)
  // and `SERVER` (callee) to identify queueing latency associated with the span.
  SpanKind kind = 14;

  // The start time of the span. On the client side, this is the time kept by
  // the local machine where the span execution starts. On the server side, this
  // is the time when the server's application handler starts running.
  //
  // This field is semantically required. When not set on receive -
  // receiver should set it to the value of end_time field if it was
  // set. Or to the current time if neither was set. It is important to
  // keep end_time > start_time for consistency.
  //
  // This field is required.
  google.protobuf.Timestamp start_time = 5;

  // The end time of the span. On the client side, this is the time kept by
  // the local machine where the span execution ends. On the server side, this
  // is the time when the server application handler stops running.
  //
  // This field is semantically required. When not set on receive -
  // receiver should set it to start_time value. It is important to
  // keep end_time > start_time for consistency.
  //
  // This field is required.
  google.protobuf.Timestamp end_time = 6;

  // A set of attributes, each with a key and a value.
  message Attributes {
    // The set of attributes. The value can be a string, an integer, a double
    // or the Boolean values `true` or `false`. Note, global attributes like 
    // server name can be set as tags using resource API. Examples of attributes:
    //
    //     "/http/user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36"
    //     "/http/server_latency": 300
    //     "abc.com/myattribute": true
    //     "abc.com/score": 10.239
    map<string, AttributeValue> attribute_map = 1;

    // The number of attributes that were discarded. Attributes can be discarded
    // because their keys are too long or because there are too many attributes.
    // If this value is 0, then no attributes were dropped.
    int32 dropped_attributes_count = 2;
  }

  // A set of attributes on the span.
  Attributes attributes = 7;

  // A stack trace captured at the start of the span.
  StackTrace stack_trace = 8;

  // A time-stamped annotation or message event in the Span.
  message TimeEvent {
    // The time the event occurred.
    google.protobuf.Timestamp time = 1;

    // A text annotation with a set of attributes.
    message Annotation {
      // A user-supplied message describing the event.
      TruncatableString description = 1;

      // A set of attributes on the annotation.
      Attributes attributes = 2;
    }

    // An event describing a message sent/received between Spans.
    message MessageEvent {
      // Indicates whether the message was sent or received.
      enum Type {
        // Unknown event type.
        TYPE_UNSPECIFIED = 0;
        // Indicates a sent message.
        SENT = 1;
        // Indicates a received message.
        RECEIVED = 2;
      }

      // The type of MessageEvent. Indicates whether the message was sent or
      // received.
      Type type = 1;

      // An identifier for the MessageEvent's message that can be used to match
      // SENT and RECEIVED MessageEvents. For example, this field could
      // represent a sequence ID for a streaming RPC. It is recommended to be
      // unique within a Span.
      uint64 id = 2;

      // The number of uncompressed bytes sent or received.
      uint64 uncompressed_size = 3;

      // The number of compressed bytes sent or received. If zero, assumed to
      // be the same size as uncompressed.
      uint64 compressed_size = 4;
    }

    // A `TimeEvent` can contain either an `Annotation` object or a
    // `MessageEvent` object, but not both.
    oneof value {
      // A text annotation with a set of attributes.
      Annotation annotation = 2;

      // An event describing a message sent/received between Spans.
      MessageEvent message_event = 3;
    }
  }

  // A collection of `TimeEvent`s. A `TimeEvent` is a time-stamped annotation
  // on the span, consisting of either user-supplied key-value pairs, or
  // details of a message sent/received between Spans.
  message TimeEvents {
    // A collection of `TimeEvent`s.
    repeated TimeEvent time_event = 1;

    // The number of dropped annotations in all the included time events.
    // If the value is 0, then no annotations were dropped.
    int32 dropped_annotations_count = 2;

    // The number of dropped message events in all the included time events.
    // If the value is 0, then no message events were dropped.
    int32 dropped_message_events_count = 3;
  }

  // The included time events.
  TimeEvents time_events = 9;

  // A pointer from the current span to another span in the same trace or in a
  // different trace. For example, this can be used in batching operations,
  // where a single batch handler processes multiple requests from different
  // traces or when the handler receives a request from a different project.
  message Link {
    // A unique identifier of a trace that this linked span is part of. The ID is a 
    // 16-byte array.
    bytes trace_id = 1;

    // A unique identifier for the linked span. The ID is an 8-byte array.
    bytes span_id = 2;

    // The relationship of the current span relative to the linked span: child,
    // parent, or unspecified.
    enum Type {
      // The relationship of the two spans is unknown, or known but other
      // than parent-child.
      TYPE_UNSPECIFIED = 0;
      // The linked span is a child of the current span.
      CHILD_LINKED_SPAN = 1;
      // The linked span is a parent of the current span.
      PARENT_LINKED_SPAN = 2;
    }

    // The relationship of the current span relative to the linked span.
    Type type = 3;

    // A set of attributes on the link.
    Attributes attributes = 4;
  }

  // A collection of links, which are references from this span to a span
  // in the same or different trace.
  message Links {
    // A collection of links.
    repeated Link link = 1;

    // The number of dropped links after the maximum size was enforced. If
    // this value is 0, then no links were dropped.
    int32 dropped_links_count = 2;
  }

  // The included links.
  Links links = 10;

  // An optional final status for this span. Semantically when Status
  // wasn't set it is means span ended without errors and assume
  // Status.Ok (code = 0).
  Status status = 11;

  // An optional resource that is associated with this span. If not set, this span 
  // should be part of a batch that does include the resource information, unless resource 
  // information is unknown.
  opencensus.proto.resource.v1.Resource resource = 16;

  // A highly recommended but not required flag that identifies when a
  // trace crosses a process boundary. True when the parent_span belongs
  // to the same process as the current span. This flag is most commonly
  // used to indicate the need to adjust time as clocks in different
  // processes may not be synchronized.
  google.protobuf.BoolValue same_process_as_parent_span = 12;

  // An optional number of child spans that were generated while this span
  // was active. If set, allows an implementation to detect missing child spans.
  google.protobuf.UInt32Value child_span_count = 13;
}

// The `Status` type defines a logical error model that is suitable for different
// programming environments, including REST APIs and RPC APIs. This proto's fields
// are a subset of those of
// [google.rpc.Status](https://github.com/googleapis/googleapis/blob/master/google/rpc/status.proto),
// which is used by [gRPC](https://github.com/grpc).
message Status {
  // The status code. This is optional field. It is safe to assume 0 (OK)
  // when not set.
  int32 code = 1;

  // A developer-facing error message, which should be in English.
  string message = 2;
}

// The value of an Attribute.
message AttributeValue {
  // The type of the value.
  oneof value {
    // A string up to 256 bytes long.
    TruncatableString string_value = 1;
    // A 64-bit signed integer.
    int64 int_value = 2;
    // A Boolean value represented by `true` or `false`.
    bool bool_value = 3;
    // A double value.
    double double_value = 4;
  }
}

// The call stack which originated this span.
message StackTrace {
  // A single stack frame in a stack trace.
  message StackFrame {
    // The fully-qualified name that uniquely identifies the function or
    // method that is active in this frame.
    TruncatableString function_name = 1;
    // An un-mangled function name, if `function_name` is
    // [mangled](http://www.avabodh.com/cxxin/namemangling.html). The name can
    // be fully qualified.
    TruncatableString original_function_name = 2;
    // The name of the source file where the function call appears.
    TruncatableString file_name = 3;
    // The line number in `file_name` where the function call appears.
    int64 line_number = 4;
    // The column number where the function call appears, if available.
    // This is important in JavaScript because of its anonymous functions.
    int64 column_number = 5;
    // The binary module from where the code was loaded.
    Module load_module = 6;
    // The version of the deployed source code.
    TruncatableString source_version = 7;
  }

  // A collection of stack frames, which can be truncated.
  message StackFrames {
    // Stack frames in this call stack.
    repeated StackFrame frame = 1;
    // The number of stack frames that were dropped because there
    // were too many stack frames.
    // If this value is 0, then no stack frames were dropped.
    int32 dropped_frames_count = 2;
  }

  // Stack frames in this stack trace.
  StackFrames stack_frames = 1;

  // The hash ID is used to conserve network bandwidth for duplicate
  // stack traces within a single trace.
  //
  // Often multiple spans will have identical stack traces.
  // The first occurrence of a stack trace should contain both
  // `stack_frames` and a value in `stack_trace_hash_id`.
  //
  // Subsequent spans within the same request can refer
  // to that stack trace by setting only `stack_trace_hash_id`.
  //
  // TODO: describe how to deal with the case where stack_trace_hash_id is
  // zero because it was not set.
  uint64 stack_trace_hash_id = 2;
}

// A description of a binary module.
message Module {
  // TODO: document the meaning of this field.
  // For example: main binary, kernel modules, and dynamic libraries
  // such as libc.so, sharedlib.so.
  TruncatableString module = 1;

  // A unique identifier for the module, usually a hash of its
  // contents.
  TruncatableString build_id = 2;
}

// A string that might be shortened to a specified length.
message TruncatableString {
  // The shortened string. For example, if the original string was 500 bytes long and
  // the limit of the string was 128 bytes, then this value contains the first 128
  // bytes of the 500-byte string. Note that truncation always happens on a
  // character boundary, to ensure that a truncated string is still valid UTF-8.
  // Because it may contain multi-byte characters, the size of the truncated string
  // may be less than the truncation limit.
  string value = 1;

  // The number of bytes removed from the original string. If this
  // value is 0, then the string was not shortened.
  int32 truncated_byte_count = 2;
}
