about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2018-05-28T20·24+0200
committerVincent Ambo <mail@tazj.in>2018-05-28T20·24+0200
commitef638bfa20d48c12960787865ec780b4e9773095 (patch)
treeb47e69b1a8b49380f0959330606bcce13b0cecf0 /src
parent0db4512df4001cdb3d9dfaa8162b3a095757c18d (diff)
feat(stackdriver): Add initial Stackdriver API type definitions
Diffstat (limited to 'src')
-rw-r--r--src/main.rs10
-rw-r--r--src/stackdriver.rs92
2 files changed, 101 insertions, 1 deletions
diff --git a/src/main.rs b/src/main.rs
index ddf9154419..7c2a53f8a1 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 0000000000..436b264244
--- /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<String, String>,
+}
+
+/// 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<Utc>,
+
+    /// A set of user-defined (key, value) data that provides
+    /// additional information about the log entry.
+    labels: HashMap<String, String>,
+}
+
+/// 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<LogEntry<'a>>,
+
+    /// 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<String, String>,
+
+    /// 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<Token, Error> {
+    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)
+}