syntax = "proto3";

package code.justin.tv.release.trace.events;
option go_package = "events";

import public "code.justin.tv/release/trace/common/common.proto";

// An Event represents a single Trace-worthy event.  This includes RPC
// lifecycle events (client started to send a request, server finishes sending
// a response), and application-specific custom events.
message Event {
	// Lifecycle event this message is attached to
	common.event.Kind kind = 1;

	// Unix epoch time in nanoseconds, as measured by the process
	sfixed64 time = 2;

	// FQDN of the process's host
	string hostname = 3;

	// Service name of the process
	string svcname = 4;

	// PID of the process
	int32 pid = 5;

	// 128-bit identifier for the entire transaction.  This field is sent as
	// two 64-bit integers, least significant word first.
	repeated fixed64 transaction_id = 6 [packed=true];

	// Identifier for a single RPC span (one request leading to one response).
	// Each level of the distributed call stack adds a new element to the path
	// field.  The value at each level is the (zero-indexed) number of
	// outbound RPC requests made at that level.
	repeated uint32 path = 7 [packed=true];

	// Additional protocol-specific information
	Extra extra = 8;

	// Amazon Resource Name for the process's EC2 instance.  This may be sent
	// instead of the hostname field.
	string ec2_arn = 20;
}

// An Extra describes protocol-specific information to be associated with an
// Event.
message Extra {

	// The address of the peer.  This could be an ipv4:port pair, [ipv6]:port
	// pair, or hostname:port pair for TCP/UDP-based protocols, a bare IP
	// address or hostname for IP- based protocols, or a path to a unix domain
	// socket.
	//
	// This field is NOT an attempt to identify the client, e.g. via the HTTP
	// X-Forwarded-For header.
	string peer = 1;

	// Additional HTTP-specific information for the Event.
	ExtraHTTP http = 2;

	// Additional SQL-specific information for the Event.
	ExtraSQL sql = 3;

	// Additional Memcached-specific information for the Event.
	ExtraMemcached memcached = 4;

	// Additional gRPC-specific information for the Event.
	ExtraGRPC grpc = 5;
}

// An ExtraHTTP describes HTTP-specific information to be associated with an
// Event.
message ExtraHTTP {
	// Status code of HTTP response.  Common values will include 200 or 404.
	// Values less than zero indicate an error observed by the client which
	// caused it to give up on the request before getting a status code from
	// the server.
	sint32 status_code = 1;

	// Method of HTTP request.
	common.http.Method method = 2;

	// Path of the HTTP request.  This is only the path - the scheme,
	// hostname, query, and fragment are not included.
	string uri_path = 16;
}

// An ExtraSQL describes SQL-specific information to be associated with an
// Event.
message ExtraSQL {
	// Name of the target database.
	string database_name = 1;

	// Username used to connect to the target database.
	string database_user = 2;

	// Query string with all user data removed: e.g. strings replaced by '',
	// integers replaced by 0, etc.  This value may be truncated (particularly
	// if it's larger than 1kB).
	string stripped_query = 16;
}

// An ExtraMemcached describes memcached-specific information to be
// associated with an event. Most of this was written with the
// assistance of the memcached protocol spec at
// https://github.com/memcached/memcached/blob/c10feb9ebe2179f6fbe4ac2e3cd12bfefdd42631/doc/protocol.txt.
message ExtraMemcached {
	// The command sent to memcached by a client
	common.memcached.Command command = 1;

	// The key sent to memcached. Note that multiple keys can be
	// fetched in one `get` request; the keys will be
	// whitespace-separated per the memcached spec.
	//
	// key is currently commented-out because of concerns around
	// confidential data residing in memcached keys.
	//
	// string key = 4;

	// The number of keys in this memcached event. This is useful
	// for understanding bulk transactions: the request side might
	// ask for 150 keys, but the response side might have only
	// 100, indicating that the cache was hit for 100 out of the
	// 150 requested keys.
	uint32 n_keys = 2;

	// Some commands involve the client setting a 32-bit integer
	// expiration time. According to the memcached protocol spec,
	// this may be either a Unix time, or a number of seconds
	// starting from current time. The memcached server decides
	// which it is by the size of the expiration time: if the
	// value is less than or equal to 60*60*24*30 (30 days), then
	// it's taken as a relative expiration; if it's over this
	// amount then it is interpreted as Unix time. If its set to
	// zero, then the item never expires.
	fixed32 expiration = 3;
}

// An ExtraGRPC describes gRPC-specific information to be associated with an
// event.
message ExtraGRPC {
	// Fully-qualified method name, including proto package name, service
	// name, and method name.
	string method = 1;
}

// An UnusedExtra describes protocol-specific information to be associated
// with an Event.  This message is not yet ready for use, meaning that the
// field names, identities, and numbers are subject to change!
message UnusedExtra {
	option deprecated = true; // not ready yet!

	// The Extra message can be attached to any Event.  The Kind of Event
	// determines the meaning of some of the fields: when payload_size is
	// specified in a REQUEST_BODY_RECEIVED event, it refers to the size of
	// the request body.  The same annotation on a RESPONSE_BODY_SENT event
	// would refer to the size of the response body.

	// we'll save fields 1-15 for later, when we know what the popular fields
	// are

	// written by an engineer - "string" means utf-8 encoded, which should be
	// fine?
	string text = 20;
	bool text_truncated = 1020;

	// if there's a payload, how big is it?
	int64 payload_size = 21;

	// HTTP

	// request uri
	string http_uri = 41;
	bool http_uri_truncated = 1041;

	// headers, partial list
	repeated KV http_header = 43;

	// if there are headers that we expect to be very long, we may want to
	// pull them out into their own fields so we can note when we truncate
	// them
	string http_referer = 44;
	bool http_referer_truncated = 1044;


	// if we use proto3 we can just use maps
	message KV {
		// option map_entry = true;
		string key = 1;
		string value = 2;
	}
}

// An EventSet is a list of Events.  It may be used when sending multiple
// events in a datagram, or when saving them to disk.  There is no codified or
// implied relation between Events grouped into an EventSet.
//
// The EventSet can just be a wrapper to indicate that it holds a
// compressed EventSet. If this is the case, the compression field
// will indicate the compression codec.
message EventSet {
	// List of Events, if (and only if) the data is uncompressed.
	repeated Event event = 1;

	// A compressed EventSet. If this is set, then the event field should be empty.
	bytes compressed_event_set = 2;

	// The compression codec used to encode compressed_event_set.
	Compression compression = 3;
}

enum Compression {
	// The data is not compressed.
	NONE = 0;
	// The data is comressed with gzip.
	GZIP = 1;
}
