//! This module defines types and functions for submitting log entries //! to the Stackdriver Logging API. //! //! Initially this will use the HTTP & JSON API instead of gRPC. //! //! Documentation for the relevant endpoint is available at: //! https://cloud.google.com/logging/docs/reference/v2/rest/v2/entries/write use chrono::{DateTime, Utc}; use failure::{Error, ResultExt}; use std::collections::HashMap; use reqwest::Client; const WRITE_ENTRY_URL: &str = "https://logging.googleapis.com/v2/entries:write"; const TOKEN_URL: &str = "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token"; /// Represents an OAuth 2 access token as returned by Google's APIs. #[derive(Deserialize)] struct Token { access_token: String, expires_in: usize, } #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] struct MonitoredResource { /// The monitored resource type. This field must match the type /// field of a MonitoredResourceDescriptor object. #[serde(rename = "type")] resource_type: String, /// Values for all of the labels listed in the associated /// monitored resource descriptor. labels: HashMap, } /// This type represents a single Stackdriver log entry. #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] struct LogEntry<'a> { /// The resource name of the log to which this log entry belongs. log_name: String, /// The primary monitored resource associated with this log entry. resource: &'a MonitoredResource, /// The time the event described by the log entry occurred. timestamp: DateTime, /// A set of user-defined (key, value) data that provides /// additional information about the log entry. labels: HashMap, } /// This type represents the request sent to the Stackdriver API to /// insert a batch of log records. #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] struct WriteEntriesRequest<'a> { /// The log entries to send to Stackdriver Logging. entries: Vec>, /// Whether valid entries should be written even if some other /// entries fail due to `INVALID_ARGUMENT` or `PERMISSION_DENIED` /// errors. partial_success: bool, /// Default labels that are added to the labels field of all log /// entries in entries. If a log entry already has a label with /// the same key as a label in this parameter, then the log /// entry's label is not changed. labels: HashMap, /// The log entry payload, represented as a Unicode string. text_payload: String, } // Define the metadata header required by Google's service: header! { (MetadataFlavor, "Metadata-Flavor") => [String] } /// This function is used to fetch a new authentication token from /// Google. Currently only tokens retrieved via instance metadata are /// supported. fn fetch_token() -> Result { let token: Token = Client::new() .get(TOKEN_URL) .header(MetadataFlavor("Google".to_string())) .send().context("Requesting token failed")? .json().context("Deserializing token failed")?; Ok(token) }