about summary refs log tree commit diff
path: root/src/stackdriver.rs
blob: 436b2642449f5502450c350a797ca815dd5c5212 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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)
}