From ef638bfa20d48c12960787865ec780b4e9773095 Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Mon, 28 May 2018 22:24:32 +0200 Subject: feat(stackdriver): Add initial Stackdriver API type definitions --- src/main.rs | 10 +++++- src/stackdriver.rs | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 src/stackdriver.rs (limited to 'src') diff --git a/src/main.rs b/src/main.rs index ddf9154419a8..7c2a53f8a161 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,16 @@ -// #[macro_use] extern crate failure; +#[macro_use] extern crate failure; +#[macro_use] extern crate hyper; #[macro_use] extern crate log; +#[macro_use] extern crate serde_derive; +extern crate chrono; extern crate env_logger; extern crate systemd; +extern crate serde; +extern crate serde_json; +extern crate reqwest; + +mod stackdriver; use systemd::journal::*; use std::process; diff --git a/src/stackdriver.rs b/src/stackdriver.rs new file mode 100644 index 000000000000..436b2642449f --- /dev/null +++ b/src/stackdriver.rs @@ -0,0 +1,92 @@ +//! 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) +} -- cgit 1.4.1