reports.proto 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. syntax = "proto3";
  2. import "google/protobuf/timestamp.proto";
  3. message Trace {
  4. message CachePolicy {
  5. enum Scope {
  6. UNKNOWN = 0;
  7. PUBLIC = 1;
  8. PRIVATE = 2;
  9. }
  10. Scope scope = 1;
  11. int64 max_age_ns = 2; // use 0 for absent, -1 for 0
  12. }
  13. message Details {
  14. // The variables associated with this query (unless the reporting agent is
  15. // configured to keep them all private). Values are JSON: ie, strings are
  16. // enclosed in double quotes, etc. The value of a private variable is
  17. // the empty string.
  18. map<string, string> variables_json = 4;
  19. // This is deprecated and only used for legacy applications
  20. // don't include this in traces inside a FullTracesReport; the operation
  21. // name for these traces comes from the key of the traces_per_query map.
  22. string operation_name = 3;
  23. }
  24. message Error {
  25. string message = 1; // required
  26. repeated Location location = 2;
  27. uint64 time_ns = 3;
  28. string json = 4;
  29. }
  30. message HTTP {
  31. message Values {
  32. repeated string value = 1;
  33. }
  34. enum Method {
  35. UNKNOWN = 0;
  36. OPTIONS = 1;
  37. GET = 2;
  38. HEAD = 3;
  39. POST = 4;
  40. PUT = 5;
  41. DELETE = 6;
  42. TRACE = 7;
  43. CONNECT = 8;
  44. PATCH = 9;
  45. }
  46. Method method = 1;
  47. string host = 2;
  48. string path = 3;
  49. // Should exclude manual blacklist ("Auth" by default)
  50. map<string, Values> request_headers = 4;
  51. map<string, Values> response_headers = 5;
  52. uint32 status_code = 6;
  53. bool secure = 8; // TLS was used
  54. string protocol = 9; // by convention "HTTP/1.0", "HTTP/1.1", "HTTP/2" or "h2"
  55. }
  56. message Location {
  57. uint32 line = 1;
  58. uint32 column = 2;
  59. }
  60. // We store information on each resolver execution as a Node on a tree.
  61. // The structure of the tree corresponds to the structure of the GraphQL
  62. // response; it does not indicate the order in which resolvers were
  63. // invoked. Note that nodes representing indexes (and the root node)
  64. // don't contain all Node fields (eg types and times).
  65. message Node {
  66. // The name of the field (for Nodes representing a resolver call) or the
  67. // index in a list (for intermediate Nodes representing elements of a list).
  68. // field_name is the name of the field as it appears in the GraphQL
  69. // response: ie, it may be an alias. (In that case, the original_field_name
  70. // field holds the actual field name from the schema.) In any context where
  71. // we're building up a path, we use the response_name rather than the
  72. // original_field_name.
  73. oneof id {
  74. string response_name = 1;
  75. uint32 index = 2;
  76. }
  77. string original_field_name = 14;
  78. // The field's return type; e.g. "String!" for User.email:String!
  79. string type = 3;
  80. // The field's parent type; e.g. "User" for User.email:String!
  81. string parent_type = 13;
  82. CachePolicy cache_policy = 5;
  83. // relative to the trace's start_time, in ns
  84. uint64 start_time = 8;
  85. // relative to the trace's start_time, in ns
  86. uint64 end_time = 9;
  87. repeated Error error = 11;
  88. repeated Node child = 12;
  89. reserved 4;
  90. }
  91. // represents a node in the query plan, under which there is a trace tree for that service fetch.
  92. // In particular, each fetch node represents a call to an implementing service, and calls to implementing
  93. // services may not be unique. See https://github.com/apollographql/apollo-server/blob/main/packages/apollo-gateway/src/QueryPlan.ts
  94. // for more information and details.
  95. message QueryPlanNode {
  96. // This represents a set of nodes to be executed sequentially by the Gateway executor
  97. message SequenceNode {
  98. repeated QueryPlanNode nodes = 1;
  99. }
  100. // This represents a set of nodes to be executed in parallel by the Gateway executor
  101. message ParallelNode {
  102. repeated QueryPlanNode nodes = 1;
  103. }
  104. // This represents a node to send an operation to an implementing service
  105. message FetchNode {
  106. // XXX When we want to include more details about the sub-operation that was
  107. // executed against this service, we should include that here in each fetch node.
  108. // This might include an operation signature, requires directive, reference resolutions, etc.
  109. string service_name = 1;
  110. bool trace_parsing_failed = 2;
  111. // This Trace only contains start_time, end_time, duration_ns, and root;
  112. // all timings were calculated **on the federated service**, and clock skew
  113. // will be handled by the ingress server.
  114. Trace trace = 3;
  115. // relative to the outer trace's start_time, in ns, measured in the gateway.
  116. uint64 sent_time_offset = 4;
  117. // Wallclock times measured in the gateway for when this operation was
  118. // sent and received.
  119. google.protobuf.Timestamp sent_time = 5;
  120. google.protobuf.Timestamp received_time = 6;
  121. }
  122. // This node represents a way to reach into the response path and attach related entities.
  123. // XXX Flatten is really not the right name and this node may be renamed in the query planner.
  124. message FlattenNode {
  125. repeated ResponsePathElement response_path = 1;
  126. QueryPlanNode node = 2;
  127. }
  128. message ResponsePathElement {
  129. oneof id {
  130. string field_name = 1;
  131. uint32 index = 2;
  132. }
  133. }
  134. oneof node {
  135. SequenceNode sequence = 1;
  136. ParallelNode parallel = 2;
  137. FetchNode fetch = 3;
  138. FlattenNode flatten = 4;
  139. }
  140. }
  141. // Wallclock time when the trace began.
  142. google.protobuf.Timestamp start_time = 4; // required
  143. // Wallclock time when the trace ended.
  144. google.protobuf.Timestamp end_time = 3; // required
  145. // High precision duration of the trace; may not equal end_time-start_time
  146. // (eg, if your machine's clock changed during the trace).
  147. uint64 duration_ns = 11; // required
  148. // A tree containing information about all resolvers run directly by this
  149. // service, including errors.
  150. Node root = 14;
  151. // -------------------------------------------------------------------------
  152. // Fields below this line are *not* included in federated traces (the traces
  153. // sent from federated services to the gateway).
  154. // In addition to details.raw_query, we include a "signature" of the query,
  155. // which can be normalized: for example, you may want to discard aliases, drop
  156. // unused operations and fragments, sort fields, etc. The most important thing
  157. // here is that the signature match the signature in StatsReports. In
  158. // StatsReports signatures show up as the key in the per_query map (with the
  159. // operation name prepended). The signature should be a valid GraphQL query.
  160. // All traces must have a signature; if this Trace is in a FullTracesReport
  161. // that signature is in the key of traces_per_query rather than in this field.
  162. // Engineproxy provides the signature in legacy_signature_needs_resigning
  163. // instead.
  164. string signature = 19;
  165. // Optional: when GraphQL parsing or validation against the GraphQL schema fails, these fields
  166. // can include reference to the operation being sent for users to dig into the set of operations
  167. // that are failing validation.
  168. string unexecutedOperationBody = 27;
  169. string unexecutedOperationName = 28;
  170. Details details = 6;
  171. // Note: engineproxy always sets client_name, client_version, and client_address to "none".
  172. // apollo-engine-reporting allows for them to be set by the user.
  173. string client_name = 7;
  174. string client_version = 8;
  175. string client_address = 9;
  176. string client_reference_id = 23;
  177. HTTP http = 10;
  178. CachePolicy cache_policy = 18;
  179. // If this Trace was created by a gateway, this is the query plan, including
  180. // sub-Traces for federated services. Note that the 'root' tree on the
  181. // top-level Trace won't contain any resolvers (though it could contain errors
  182. // that occurred in the gateway itself).
  183. QueryPlanNode query_plan = 26;
  184. // Was this response served from a full query response cache? (In that case
  185. // the node tree will have no resolvers.)
  186. bool full_query_cache_hit = 20;
  187. // Was this query specified successfully as a persisted query hash?
  188. bool persisted_query_hit = 21;
  189. // Did this query contain both a full query string and a persisted query hash?
  190. // (This typically means that a previous request was rejected as an unknown
  191. // persisted query.)
  192. bool persisted_query_register = 22;
  193. // Was this operation registered and a part of the safelist?
  194. bool registered_operation = 24;
  195. // Was this operation forbidden due to lack of safelisting?
  196. bool forbidden_operation = 25;
  197. // removed: Node parse = 12; Node validate = 13;
  198. // Id128 server_id = 1; Id128 client_id = 2;
  199. reserved 12, 13, 1, 2;
  200. }
  201. // The `service` value embedded within the header key is not guaranteed to contain an actual service,
  202. // and, in most cases, the service information is trusted to come from upstream processing. If the
  203. // service _is_ specified in this header, then it is checked to match the context that is reporting it.
  204. // Otherwise, the service information is deduced from the token context of the reporter and then sent
  205. // along via other mechanisms (in Kafka, the `ReportKafkaKey). The other information (hostname,
  206. // agent_version, etc.) is sent by the Apollo Engine Reporting agent, but we do not currently save that
  207. // information to any of our persistent storage.
  208. message ReportHeader {
  209. // eg "mygraph@myvariant"
  210. string graph_ref = 12;
  211. // eg "host-01.example.com"
  212. string hostname = 5;
  213. // eg "engineproxy 0.1.0"
  214. string agent_version = 6; // required
  215. // eg "prod-4279-20160804T065423Z-5-g3cf0aa8" (taken from `git describe --tags`)
  216. string service_version = 7;
  217. // eg "node v4.6.0"
  218. string runtime_version = 8;
  219. // eg "Linux box 4.6.5-1-ec2 #1 SMP Mon Aug 1 02:31:38 PDT 2016 x86_64 GNU/Linux"
  220. string uname = 9;
  221. // An id that is used to represent the schema to Apollo Graph Manager
  222. // Using this in place of what used to be schema_hash, since that is no longer
  223. // attached to a schema in the backend.
  224. string executable_schema_id = 11;
  225. reserved 3; // removed string service = 3;
  226. }
  227. message PathErrorStats {
  228. map<string, PathErrorStats> children = 1;
  229. uint64 errors_count = 4;
  230. uint64 requests_with_errors_count = 5;
  231. }
  232. message QueryLatencyStats {
  233. repeated sint64 latency_count = 13 [(js_use_toArray)=true];
  234. uint64 request_count = 2;
  235. uint64 cache_hits = 3;
  236. uint64 persisted_query_hits = 4;
  237. uint64 persisted_query_misses = 5;
  238. repeated sint64 cache_latency_count = 14 [(js_use_toArray)=true];
  239. PathErrorStats root_error_stats = 7;
  240. uint64 requests_with_errors_count = 8;
  241. repeated sint64 public_cache_ttl_count = 15 [(js_use_toArray)=true];
  242. repeated sint64 private_cache_ttl_count = 16 [(js_use_toArray)=true];
  243. uint64 registered_operation_count = 11;
  244. uint64 forbidden_operation_count = 12;
  245. // 1, 6, 9, and 10 were old int64 histograms
  246. reserved 1, 6, 9, 10;
  247. }
  248. message StatsContext {
  249. string client_reference_id = 1;
  250. string client_name = 2;
  251. string client_version = 3;
  252. }
  253. message ContextualizedQueryLatencyStats {
  254. QueryLatencyStats query_latency_stats = 1;
  255. StatsContext context = 2;
  256. }
  257. message ContextualizedTypeStats {
  258. StatsContext context = 1;
  259. map<string, TypeStat> per_type_stat = 2;
  260. }
  261. message FieldStat {
  262. string return_type = 3; // required; eg "String!" for User.email:String!
  263. uint64 errors_count = 4;
  264. uint64 count = 5;
  265. uint64 requests_with_errors_count = 6;
  266. repeated sint64 latency_count = 9 [(js_use_toArray)=true]; // Duration histogram; see docs/histograms.md
  267. reserved 1, 2, 7, 8;
  268. }
  269. message TypeStat {
  270. // Key is (eg) "email" for User.email:String!
  271. map<string, FieldStat> per_field_stat = 3;
  272. reserved 1, 2;
  273. }
  274. message Field {
  275. string name = 2; // required; eg "email" for User.email:String!
  276. string return_type = 3; // required; eg "String!" for User.email:String!
  277. }
  278. message Type {
  279. string name = 1; // required; eg "User" for User.email:String!
  280. repeated Field field = 2;
  281. }
  282. // This is the top-level message used by the new traces ingress. This
  283. // is designed for the apollo-engine-reporting TypeScript agent and will
  284. // eventually be documented as a public ingress API. This message consists
  285. // solely of traces; the equivalent of the StatsReport is automatically
  286. // generated server-side from this message. Agent should either send a trace or include it in the stats
  287. // for every request in this report. Generally, buffering up until a large
  288. // size has been reached (say, 4MB) or 5-10 seconds has passed is appropriate.
  289. // This message used to be know as FullTracesReport, but got renamed since it isn't just for traces anymore
  290. message Report {
  291. ReportHeader header = 1;
  292. // key is statsReportKey (# operationName\nsignature) Note that the nested
  293. // traces will *not* have a signature or details.operationName (because the
  294. // key is adequate).
  295. //
  296. // We also assume that traces don't have
  297. // legacy_per_query_implicit_operation_name, and we don't require them to have
  298. // details.raw_query (which would consume a lot of space and has privacy/data
  299. // access issues, and isn't currently exposed by our app anyway).
  300. map<string, TracesAndStats> traces_per_query = 5;
  301. // This is the time that the requests in this trace are considered to have taken place
  302. // If this field is not present the max of the end_time of each trace will be used instead.
  303. // If there are no traces and no end_time present the report will not be able to be processed.
  304. // Note: This will override the end_time from traces.
  305. google.protobuf.Timestamp end_time = 2; // required if no traces in this message
  306. }
  307. message ContextualizedStats {
  308. StatsContext context = 1;
  309. QueryLatencyStats query_latency_stats = 2;
  310. // Key is type name.
  311. map<string, TypeStat> per_type_stat = 3;
  312. }
  313. // A sequence of traces and stats. An individual trace should either be counted as a stat or trace
  314. message TracesAndStats {
  315. repeated Trace trace = 1 [(js_preEncoded)=true];
  316. repeated ContextualizedStats stats_with_context = 2 [(js_use_toArray)=true];
  317. // This field is used to validate that the algorithm used to construct `stats_with_context`
  318. // matches similar algorithms in Apollo's servers. It is otherwise ignored and should not
  319. // be included in reports.
  320. repeated Trace internal_traces_contributing_to_stats = 3 [(js_preEncoded)=true];
  321. }