diff options
author | Vincent Ambo <tazjin@gmail.com> | 2018-06-17T15·03+0200 |
---|---|---|
committer | Vincent Ambo <github@tazj.in> | 2018-06-17T15·43+0200 |
commit | 79afc5f474ec9ccb6a80445c5eab8d38e115f22d (patch) | |
tree | 1840b3a46a3da4b5296eafd0b1c6a7fbd9f19029 | |
parent | 62745db1a0f9fe0bf77849661f4e0d2ecc992914 (diff) |
feat(main): Support manually configured resource descriptors
Lets users specify environment variables to configure the monitored resource descriptor. In combination with service account support this can be used to configure journaldriver on non-GCP machines. The supported environment variables are: * `GOOGLE_CLOUD_PROJECT`: Project ID of the project to which to report logs * `LOG_NAME`: Name of the Stackdriver Logging log into which to write entries
-rw-r--r-- | src/main.rs | 88 |
1 files changed, 57 insertions, 31 deletions
diff --git a/src/main.rs b/src/main.rs index b96467f643dd..9db3c94ecf39 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,16 +21,15 @@ //! to Stackdriver in batches. //! //! Stackdriver Logging has a concept of monitored resources. In the -//! simplest (and currently only supported) case this monitored -//! resource will be the GCE instance on which journaldriver is -//! running. +//! simplest case this monitored resource will be the GCE instance on +//! which journaldriver is running. //! //! Information about the instance, the project and required security //! credentials are retrieved from Google's metadata instance on GCP. //! -//! Things left to do: -//! * TODO 2018-06-15: Support non-GCP instances (see comment on -//! monitored resource descriptor) +//! To run journaldriver on non-GCP machines, users must specify the +//! `GOOGLE_APPLICATION_CREDENTIALS`, `GOOGLE_CLOUD_PROJECT` and +//! `LOG_NAME` environment variables. #[macro_use] extern crate failure; #[macro_use] extern crate hyper; @@ -103,17 +102,13 @@ lazy_static! { .build().expect("Could not create metadata client") }; - /// ID of the GCP project in which this instance is running. - static ref PROJECT_ID: String = get_metadata(METADATA_PROJECT_URL) - .expect("Could not determine project ID"); + /// ID of the GCP project to which to send logs. + static ref PROJECT_ID: String = get_project_id(); - /// ID of the current GCP instance. - static ref INSTANCE_ID: String = get_metadata(METADATA_ID_URL) - .expect("Could not determine instance ID"); - - /// GCP zone in which this instance is running. - static ref ZONE: String = get_metadata(METADATA_ZONE_URL) - .expect("Could not determine instance zone"); + /// Name of the log to write to (this should only be manually + /// configured if not running on GCP): + static ref LOG_NAME: String = env::var("LOG_NAME") + .unwrap_or("journaldriver".into()); /// Service account credentials (if configured) static ref SERVICE_ACCOUNT_CREDENTIALS: Option<Credentials> = @@ -121,20 +116,10 @@ lazy_static! { .and_then(|path| File::open(path).ok()) .and_then(|file| serde_json::from_reader(file).ok()); - /// Descriptor of the currently monitored instance. - /// - /// For GCE instances, this will be the GCE instance ID. For - /// non-GCE machines a sensible solution may be using the machine - /// hostname as a Cloud Logging log name, but this is not yet - /// implemented. - static ref MONITORED_RESOURCE: Value = json!({ - "type": "gce_instance", - "labels": { - "project_id": PROJECT_ID.as_str(), - "instance_id": INSTANCE_ID.as_str(), - "zone": ZONE.as_str(), - } - }); + /// Descriptor of the currently monitored instance. Refer to the + /// documentation of `determine_monitored_resource` for more + /// information. + static ref MONITORED_RESOURCE: Value = determine_monitored_resource(); /// Path to the file in which journaldriver should persist its /// cursor state. @@ -153,6 +138,47 @@ fn get_metadata(url: &str) -> Result<String> { Ok(output.trim().into()) } +/// Convenience helper for determining the project ID. +fn get_project_id() -> String { + env::var("GOOGLE_CLOUD_PROJECT") + .map_err(Into::into) + .or_else(|_: failure::Error| get_metadata(METADATA_PROJECT_URL)) + .expect("Could not determine project ID") +} + +/// Determines the monitored resource descriptor used in Stackdriver +/// logs. On GCP this will be set to the instance ID as returned by +/// the metadata server. +/// +/// On non-GCP machines the value is determined by using the +/// `GOOGLE_CLOUD_PROJECT` and `LOG_NAME` environment variables. +fn determine_monitored_resource() -> Value { + if let Ok(log) = env::var("LOG_NAME") { + json!({ + "type": "logging_log", + "labels": { + "project_id": PROJECT_ID.as_str(), + "name": log, + } + }) + } else { + let instance_id = get_metadata(METADATA_ID_URL) + .expect("Could not determine instance ID"); + + let zone = get_metadata(METADATA_ZONE_URL) + .expect("Could not determine instance zone"); + + json!({ + "type": "gce_instance", + "labels": { + "project_id": PROJECT_ID.as_str(), + "instance_id": instance_id, + "zone": zone, + } + }) + } +} + /// Represents the response returned by the metadata server's token /// endpoint. The token is normally valid for an hour. #[derive(Deserialize)] @@ -456,7 +482,7 @@ fn flush(client: &Client, /// https://cloud.google.com/logging/docs/reference/v2/rest/v2/entries/write fn prepare_request(entries: &[LogEntry]) -> Value { json!({ - "logName": format!("projects/{}/logs/journaldriver", PROJECT_ID.as_str()), + "logName": format!("projects/{}/logs/{}", PROJECT_ID.as_str(), LOG_NAME.as_str()), "resource": &*MONITORED_RESOURCE, "entries": entries, "partialSuccess": true |