1// Copyright 2018 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5library fuchsia.cobalt; 6 7using fuchsia.mem; 8 9// Cobalt is the Fuchsia service used to log, collect and analyze metrics. 10// The two main pillars of Cobalt are protecting user privacy and providing 11// high-quality, aggregate metrics to serve system and component software 12// developers' needs. 13// 14// This file contains interfaces that allow clients to log Events to 15// Cobalt. 16// 17// To use Cobalt, you must have a Project and one or more Metrics registered 18// with the Cobalt registration system. You must also register one or more 19// Reports in order to see the results of your logging aggregated over 20// all Fuchsia devices. Registration of Projects, Metrics and Reports consists 21// of entries in the YAML files in this repo: 22// https://cobalt-analytics.googlesource.com/config/. 23// In a Garnet checkout that is mapped to //third_party/cobalt_config. 24// Each registered object has an integer ID and those IDs are used as 25// parameters in the methods in this file. 26// 27// While Cobalt's code and registration files are open source, the running 28// system being managed by the Cobalt team is currently intended to be used by 29// software engineers at Google in order to collect metrics in a way that 30// preserves our users' privacy. If you are a Google software engineer 31// please see our internal [user guide](go/fuchsia-cobalt-userguide) or 32// ask for assistance from the Cobalt [team](go/fuchsia-cobalt#comms). 33// 34// Usage: First use LoggerFactory to get a Logger for your 35// project. Then you log Events using the Log*() methods. 36// Events are accumulated by the cobalt FIDL service and periodically 37// Observations, derived from the logged Events, are sent to the Cobalt server, 38// where they are used to generate Reports. 39 40// The maximum size of a single Event is 100 KB. 41const int64 MAX_BYTES_PER_EVENT = 102400; 42 43// Response codes for Logger operations. 44enum Status : int32 { 45 OK = 0; 46 47 // For example the supplied metric id is invalid. 48 INVALID_ARGUMENTS = 1; 49 50 // An attempt was made to log an Event whose seralized size exceeds 51 // MAX_BYTES_PER_EVENT. 52 EVENT_TOO_BIG = 2; 53 54 // Cobalt's local buffer is temporarily full and cannot handle any more 55 // Events at this time. Try again later. This condition should be rare 56 BUFFER_FULL = 3; 57 58 // Catch-all for unexpected errors. 59 INTERNAL_ERROR = -1; 60}; 61 62// The release stage of a client's project is used to decide which 63// metrics are allowed to be collected. 64enum ReleaseStage : int32 { 65 // Only metrics targetting GA releases will be sent to the server. 66 GA = 0; 67 68 // Metrics targetting DOGFOOD and GA will be sent to the server. 69 DOGFOOD = 10; 70 71 // Metrics targetting FISHFOOD, DOGFOOD and GA will be sent to the server. 72 FISHFOOD = 20; 73 74 // All metrics will be sent to the server. 75 DEBUG = 99; 76}; 77 78// A ProjectProfile is used to describe the client's Cobalt project 79struct ProjectProfile { 80 // The |config| Buffer contains the bytes of a serialized Cobalt config 81 // proto message. This specifies registered Metric and Report definitions 82 // for a single project. 83 fuchsia.mem.Buffer config; 84 85 // The release stage of the client's project. 86 ReleaseStage release_stage; 87}; 88 89[Discoverable, Layout = "Simple"] 90// LoggerFactory creates Loggers. 91interface LoggerFactory { 92 // Creates a Logger for the given ProjectProfile. 93 // 94 // |profile| A ProjectProfile describing the Cobalt project that the 95 // returned Logger is for. 96 // 97 // |status| Returns OK on success or INVALID_ARGUMENTS if the project 98 // profile does not contain a valid Cobalt config with only a single 99 // project_id. 100 1: CreateLogger(ProjectProfile profile, 101 request<Logger> logger) 102 -> (Status status); 103 104 // Creates a LoggerSimple for the given ProjectProfile. 105 // 106 // |profile| A ProjectProfile describing the Cobalt project that the 107 // returned Logger is for. 108 // 109 // |status| Returns OK on success or INVALID_ARGUMENTS if the project 110 // profile does not contain a valid Cobalt config with only a single 111 // project_id. 112 2: CreateLoggerSimple(ProjectProfile profile, 113 request<LoggerSimple> logger) 114 -> (Status status); 115}; 116 117///////////////////////////////////////////////////////////////////// 118// LoggerBase Interface 119///////////////////////////////////////////////////////////////////// 120 121// LoggerBase and its extensions are used to log Events to the Cobalt system. 122// The Cobalt FIDL service stores the Events locally for some period of time, 123// processes the Events to form Observations, and periodically uploads batches 124// of Observations to the Cobalt server. The Cobalt server processes the 125// Observations and generates Reports. See [TODO(rudominer)] for more 126// description of the Cobalt server and Reports. 127// 128// LoggerBase or one of its extensions is associated with a single Cobalt 129// project. 130// 131// This interface conforms to the Simple layout so that Simple bindings 132// may be generated for it. For the full interfaces, see Logger and LoggerSimple 133// below. 134[Layout = "Simple"] 135interface LoggerBase { 136 // Logs the fact that an event has occurred. 137 // 138 // |metric_id| ID of the metric to use. It must be one of the Metrics 139 // from the ProjectProfile used to obtain this Logger, and it must be of 140 // type EVENT_OCCURRED. 141 // 142 // |event_type_index| The index of the event type that occurred. The indexed 143 // set of all event types is specified in the metric definition. 144 1: LogEvent(uint32 metric_id, uint32 event_type_index) 145 -> (Status status); 146 147 // Logs that an event has occurred a given number of times. 148 // 149 // |metric_id| ID of the metric to use. It must be one of the Metrics 150 // from the ProjectProfile used to obtain this Logger, and it must be of 151 // type EVENT_COUNT. 152 // 153 // |event_type_index| The index of the event type that occurred. The indexed 154 // set of all event types is specified in the metric definition. 155 // 156 // |component| Optionally, a component associated with the event may 157 // also be logged. Any notion of component that makes sense may be 158 // used or use the empty string if there is no natural notion of 159 // component. 160 // 161 // |period_duration_micros| Optionally, the period of time over which 162 // the |count| events occurred may be logged. If this is not 163 // relevant the value may be set to 0. Otherwise specify the period 164 // duration as a number of microseconds. 165 // 166 // |count| The number of times the event occurred. One may choose to 167 // always set this value to 1 and always set 168 // |period_duration_micros| to 0 in order to achieve a semantics 169 // similar to the LogEventOccurred() method, but with a |component|. 170 2: LogEventCount(uint32 metric_id, uint32 event_type_index, 171 string:64 component, int64 period_duration_micros, 172 int64 count) 173 -> (Status status); 174 175 // Logs that an event lasted a given amount of time. 176 // 177 // |metric_id| ID of the metric to use. It must be one of the Metrics 178 // from the ProjectProfile used to obtain this Logger, and it must be of 179 // type ELAPSED_TIME. 180 // 181 // |event_type_index| The index of the event type that occurred. The indexed 182 // set of all event types is specified in the metric definition. 183 // 184 // |component| Optionally, a component associated with the event may 185 // also be logged. Any notion of component that makes sense may be 186 // used or use the empty string if there is no natural notion of 187 // component. 188 // 189 // |elapsed_micros| The elapsed time of the event, specified as a number 190 // of microseconds. 191 3: LogElapsedTime(uint32 metric_id, uint32 event_type_index, 192 string:64 component, int64 elapsed_micros) 193 -> (Status status); 194 195 // Logs a measured average frame rate. 196 // 197 // |metric_id| ID of the metric to use. It must be one of the Metrics 198 // from the ProjectProfile used to obtain this Logger, and it must be of 199 // type FRAME_RATE. 200 // 201 // |event_type_index| The index of the event type that associated with the 202 // frame-rate measurement. The indexed set of all event types is 203 // specified in the metric definition. 204 // 205 // |component| Optionally, a component associated with the frame-rate 206 // measurement may also be logged. Any notion of component that makes 207 // sense may be used or use the empty string if there is no natural 208 // notion of component. 209 // 210 // |fps| The average-frame rate in frames-per-second. 211 4: LogFrameRate(uint32 metric_id, uint32 event_type_index, 212 string:64 component, float32 fps) 213 -> (Status status); 214 215 // Logs a measured memory usage. 216 // 217 // |metric_id| ID of the metric to use. It must be one of the Metrics 218 // from the ProjectProfile used to obtain this Logger, and it must be of 219 // type MEMORY_USAGE. 220 // 221 // |event_type_index| The index of the event type associated with the memory 222 // usage. The indexed set of all event types is specified in the metric 223 // definition. 224 // 225 // |component| Optionally, a component associated with the memory usage 226 // may also be logged. Any notion of component that makes sense may be 227 // used or use the empty string if there is no natural notion of 228 // component. 229 // 230 // |bytes| The memory used, in bytes. 231 5: LogMemoryUsage(uint32 metric_id, uint32 event_type_index, 232 string:64 component, int64 bytes) 233 -> (Status status); 234 235 // Logs the fact that a given string was used, in a specific context. 236 // The semantics of the context and the string is specified in the 237 // Metric definition. 238 // 239 // This method is intended to be used in the following situation: 240 // * The string s being logged does not contain PII or passwords. 241 // * The set S of all possible strings that may be logged is large. 242 // If the set S is small consider using LogEvent() instead. 243 // * The ultimate data of interest is the statistical distribution of the 244 // most commonly used strings from S over the population of all Fuchsia 245 // devices. 246 // 247 // |metric_id| ID of the metric to use. It must be one of the Metrics 248 // from the ProjectProfile used to obtain this Logger, and it must be of 249 // type STRING_USED. 250 // 251 // |s| The string to log. This should be a human-readable string of 252 // size no more than 256 bytes. 253 6: LogString(uint32 metric_id, string:256 s) -> (Status status); 254 255 // This method is part of Cobalt's helper service for measuring the time 256 // delta between two events that occur in different processes. This starts 257 // the timer. A corresponding invocation of EndTimer() with the same 258 // |timer_id| ends the timer. After both StartTimer() and EnvdTimer() have 259 // been invoked, LogElapsedTime() will be invoked with the difference 260 // between the end timestamp and the start timestamp as the value of 261 // |duration_microseconds|. It is OK if Cobalt receives the EndTimer() 262 // call before the StartTimer() call. 263 // 264 // |metric_id| ID of the metric to use. It must be one of the Metrics 265 // from the ProjectProfile used to obtain this Logger, and it must be of 266 // type ELAPSED_TIME. 267 // 268 // |event_type_index| The index of the event type to associate with the 269 // elapsed time. This is passed to LogElapsedTime() 270 // 271 // |component| Optionally, a component associated with the event may 272 // also be logged. See the description at LogElapsedTime(). 273 // 274 // |timer_id| The ID of the timer being started. This is an arbitrary 275 // non-empty string provided by the caller and it is the caller's 276 // responsibility to ensure that Cobalt receives a pair of 277 // StartTimer(), EndTimer() calls with this id before the timeout 278 // and without any intervening additional calls to StartTimer() 279 // or EndTimer() using the same id. Once such a pair is received 280 // Cobalt will delete the timer with this ID and after that the 281 // ID may be re-used. 282 // 283 // |timestamp| The timestamp to set as the start of the timer. The units 284 // must be microseconds. The absolute value does not matter, only the 285 // difference between the end and start timestamps will be used. 286 // 287 // |timeout_s| The number of seconds Cobalt should wait to receive the 288 // corresponding EndTimer() call with the same |timer_id|. If 289 // Cobalt has already received the corresponding EndTimer() call 290 // before receiving this StartTimer() call then this value is 291 // ignored as the timeout has already been set by the EndTimer() 292 // call. If Cobalt does not receive the corresponding EndTimer() 293 // call before the timeout then the timer will be deleted and 294 // this invocation of StartTimer() will be forgotten. Must be a 295 // positive value less than 300. 296 // 297 // |status| Returns OK on success. There are two success cases: 298 // (i) Cobalt does not currently have any timers with the given 299 // timer_id. In that case this call creates a new timer with 300 // the given ID and start timestamp. 301 // (ii) Cobalt currently has a timer with the given timer_id for 302 // which it has received exactly one EndTimer() call and no 303 // StartTimer() calls. In this case Cobalt will delete the 304 // timer and invoke LogElapsedTime() using the difference 305 // between the end timestamp and the start timestamp as the 306 // value of |duration_micors|. It is ok if this value is 307 // negative. 308 // Returns INVALID_ARGUMENTS if |timer_id| is empty, the timeout 309 // is not positive and less than 5 minutes or Cobalt currently 310 // has a timer with the given timer_ID and it already has a start 311 // timestamp. In the last case Cobalt will delete the timer with 312 // the given |timer_id| and this invocation of StartTimer() 313 // will be forgotten. 314 // Any error returned by LogElapsedTime() may also be returned by this 315 // method. 316 7: StartTimer(uint32 metric_id, uint32 event_type_index, 317 string:64 component, string:64 timer_id, 318 uint64 timestamp, uint32 timeout_s) 319 -> (Status status); 320 321 // This method is part of Cobalt's helper service for measuring the time 322 // delta between two events that occur in different processes. This ends 323 // the timer. A corresponding invocation of StartTimer() with the same 324 // |timer_id| starts the timer. After both StartTimer() and EnvdTimer() have 325 // been invoked, LogElapsedTime() will be invoked with the difference 326 // between the end timestamp and the start timestamp as the value of 327 // |duration_microseconds|. It is OK if Cobalt receives the EndTimer() 328 // call before the StartTimer() call. 329 // 330 // |timer_id| The ID of the timer being ended. This is an arbitrary 331 // non-empty string provided by the caller and it is the caller's 332 // responsibility to ensure that Cobalt receives a pair of 333 // StartTimer(), EndTimer() calls with this id before the timeout 334 // and without any intervening additional calls to StartTimer() 335 // or EndTimer() using the same id. Once such a pair is received 336 // Cobalt will delete the timer with this ID and after that the 337 // ID may be re-used. 338 // 339 // |timestamp| The timestamp to set as the end of the timer. The units 340 // must be microseconds. The absolute value does not matter, only the 341 // difference between the end and start timestamps will be used. 342 // 343 // |timeout_s| The number of seconds Cobalt should wait to receive the 344 // corresponding EndTimer() call with the same |timer_id|. If 345 // Cobalt has already received the corresponding EndTimer() call 346 // before receiving this StartTimer() call then this value is 347 // ignored as the timeout has already been set by the EndTimer() 348 // call. If Cobalt does not receive the corresponding EndTimer() 349 // call before the timeout then the timer will be deleted and 350 // this invocation of StartTimer() will be forgotten. Must be a 351 // positive value less than 300. 352 // 353 // |status| Returns OK on success. There are two success cases: 354 // (i) Cobalt does not currently have any timers with the given 355 // timer_id. In that case this call creates a new timer with 356 // the given ID and end timestamp. 357 // (ii) Cobalt currently has a timer with the given timer_id for 358 // which it has received exactly one StartTimer() call and no 359 // EndTimer() calls. In this case Cobalt will delete the 360 // timer and invoke LogElapsedTime() using the difference 361 // between the end timestamp and the start timestamp as the 362 // value of |duration_micors|. It is ok if this value is 363 // negative. 364 // Returns INVALID_ARGUMENTS if |timer_id| is empty, the timeout 365 // is not positive and less than 5 minutes or Cobalt currently 366 // has a timer with the given timer_ID and it already has an end 367 // timestamp. In the last case Cobalt will delete the timer with 368 // the given |timer_id| and this invocation of EndTimer() 369 // will be forgotten. 370 // Any error returned by LogElapsedTime() may also be returned by this 371 // method. 372 8: EndTimer(string:64 timer_id, uint64 timestamp, uint32 timeout_s) 373 -> (Status status); 374 375 // Method ordinals >= 100 are reserved for sub-interfaces. 376}; 377 378///////////////////////////////////////////////////////////////////// 379// Logger Interface 380///////////////////////////////////////////////////////////////////// 381 382// A value for a custom Event. This is used by the method LogCustomEvent(). 383struct CustomEventValue { 384 // The name of the Metric dimension this value is for. 385 string dimension_name; 386 387 // The value for that dimension. 388 Value value; 389}; 390 391// A value that may be a string, int, double, or index. 392union Value { 393 string string_value; 394 int64 int_value; 395 float64 double_value; 396 uint32 index_value; 397}; 398 399// One bucket of histogram. This is used by the method LogIntHistogram(). 400struct HistogramBucket { 401 // The index of the bucket. The meaning of the bucket is specified in the 402 // Metric definition. 403 uint32 index; 404 405 // The number of values in that bucket. 406 uint64 count; 407}; 408 409// Logger is an extension of the LoggerBase interface that adds some additional 410// methods that do not naturally conform to the Simple layout. We opt for 411// a natural easy-to-understand interface at the cost of not being "Simple". 412// See the interface LoggerSimple below for versions of some of these methods 413// that do conform to the Simple layout. 414interface Logger : LoggerBase { 415 // Logs a histogram over a set of integer buckets. The meaning of the 416 // Metric and the buckets is specified in the Metric definition. 417 // 418 // This method is intended to be used in situations where the client 419 // wishes to aggregate a large number of integer-valued measurements 420 // *in-process*, prior to submitting the data to Cobalt. 421 // One reason a client may wish to do this is that the measurements occur 422 // with very high frequency and it is not practical to make a FIDL call 423 // for each individual measurement. 424 // 425 // |metric_id| ID of the metric to use. It must be one of the Metrics 426 // from the ProjectProfile used to obtain this Logger, and it must be of 427 // type INT_HISTOGRAM. 428 // 429 // |event_type_index| The index of the event type associated with the 430 // integer-valued measurement. The indexed set of all event types is 431 // specified in the metric definition. 432 // 433 // |component| Optionally, a component associated with integer-valued 434 // measurements may also be logged. Any notion of component that makes 435 // sense may be used or use the empty string if there is no natural 436 // notion of component. 437 // 438 // |histogram| The histogram to log. Each HistogramBucket gives the count 439 // for one bucket of the histogram. The definitions of the buckets is 440 // given in the Metric definition. 441 100: LogIntHistogram(uint32 metric_id, uint32 event_type_index, 442 string:64 component, vector<HistogramBucket> histogram) 443 -> (Status status); 444 445 // Logs a custom Event. The semantics of the Metric are specified in the 446 // Metric defintion. 447 // 448 // |metric_id| ID of the metric to use. It must be one of the Metrics 449 // from the ProjectProfile used to obtain this Logger, and it must be of 450 // type CUSTOM. 451 // 452 // |event_values| The values for the custom Event. There is one value for 453 // each dimension of the Metric. The number and types of the values must 454 // be consistent with the dimensions declared in the Metric definition. 455 101: LogCustomEvent(uint32 metric_id, 456 vector<CustomEventValue> event_values) 457 -> (Status status); 458}; 459 460///////////////////////////////////////////////////////////////////// 461// LoggerSimple Interface 462///////////////////////////////////////////////////////////////////// 463 464// LoggerSimple is an extension of the LoggerBase interface that adds some 465// additional methods intended to be used by lower-levels of the Fuchsia system. 466// 467// This interface conforms to the Simple layout so that Simple bindings 468// may be generated for it. 469[Layout = "Simple"] 470interface LoggerSimple : LoggerBase { 471 // Logs a histogram over a set of integer buckets. The meaning of the 472 // Metric and the buckets is specified in the Metric definition. 473 // 474 // See the method LogIntHistogram() in the Logger interface for more 475 // information. This method is similar except that it adheres to the 476 // requirements of Simple layout. Instead of a vector of HistogramBucekts 477 // this version takes two parallel vectors of bucket indices and the 478 // corresponding bucket counts. 479 100: LogIntHistogram(uint32 metric_id, uint32 event_type_index, 480 string:64 component, 481 vector<uint32>:100 bucket_indices, 482 vector<uint64>:100 bucket_counts) 483 -> (Status status); 484}; 485 486///////////////////////////////////////////////////////////////////// 487// SystemProfileUpdater Interface 488///////////////////////////////////////////////////////////////////// 489 490// The state of a single experiment on a device or binary. 491struct Experiment { 492 // The id of the experiment as defined by the A/B Experiment framework. 493 uint64 experiment_id; 494 // The id of the experiment arm as definedby the A/B Experiment framework. 495 uint32 arm_id; 496}; 497 498[Discoverable] 499// The SystemDataUpdater interface allows callers to update the state of 500// the System Data in Cobalt. This includes the SystemProfile and experiment 501// state. The changes are global and affect all loggers running on the device. 502interface SystemDataUpdater { 503 // Resets Cobalt's view of the system-wide experiment state and replaces it 504 // with the given values. 505 // 506 // |experiments| All experiments the device has a notion of and the 507 // arms the device belongs to for each of them. These are the only 508 // experiments the device can collect data for. 509 1: SetExperimentState(vector<Experiment> experiments) 510 -> (Status status); 511};