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
This commit is contained in:
parent
62745db1a0
commit
79afc5f474
1 changed files with 57 additions and 31 deletions
88
src/main.rs
88
src/main.rs
|
@ -21,16 +21,15 @@
|
||||||
//! to Stackdriver in batches.
|
//! to Stackdriver in batches.
|
||||||
//!
|
//!
|
||||||
//! Stackdriver Logging has a concept of monitored resources. In the
|
//! Stackdriver Logging has a concept of monitored resources. In the
|
||||||
//! simplest (and currently only supported) case this monitored
|
//! simplest case this monitored resource will be the GCE instance on
|
||||||
//! resource will be the GCE instance on which journaldriver is
|
//! which journaldriver is running.
|
||||||
//! running.
|
|
||||||
//!
|
//!
|
||||||
//! Information about the instance, the project and required security
|
//! Information about the instance, the project and required security
|
||||||
//! credentials are retrieved from Google's metadata instance on GCP.
|
//! credentials are retrieved from Google's metadata instance on GCP.
|
||||||
//!
|
//!
|
||||||
//! Things left to do:
|
//! To run journaldriver on non-GCP machines, users must specify the
|
||||||
//! * TODO 2018-06-15: Support non-GCP instances (see comment on
|
//! `GOOGLE_APPLICATION_CREDENTIALS`, `GOOGLE_CLOUD_PROJECT` and
|
||||||
//! monitored resource descriptor)
|
//! `LOG_NAME` environment variables.
|
||||||
|
|
||||||
#[macro_use] extern crate failure;
|
#[macro_use] extern crate failure;
|
||||||
#[macro_use] extern crate hyper;
|
#[macro_use] extern crate hyper;
|
||||||
|
@ -103,17 +102,13 @@ lazy_static! {
|
||||||
.build().expect("Could not create metadata client")
|
.build().expect("Could not create metadata client")
|
||||||
};
|
};
|
||||||
|
|
||||||
/// ID of the GCP project in which this instance is running.
|
/// ID of the GCP project to which to send logs.
|
||||||
static ref PROJECT_ID: String = get_metadata(METADATA_PROJECT_URL)
|
static ref PROJECT_ID: String = get_project_id();
|
||||||
.expect("Could not determine project ID");
|
|
||||||
|
|
||||||
/// ID of the current GCP instance.
|
/// Name of the log to write to (this should only be manually
|
||||||
static ref INSTANCE_ID: String = get_metadata(METADATA_ID_URL)
|
/// configured if not running on GCP):
|
||||||
.expect("Could not determine instance ID");
|
static ref LOG_NAME: String = env::var("LOG_NAME")
|
||||||
|
.unwrap_or("journaldriver".into());
|
||||||
/// GCP zone in which this instance is running.
|
|
||||||
static ref ZONE: String = get_metadata(METADATA_ZONE_URL)
|
|
||||||
.expect("Could not determine instance zone");
|
|
||||||
|
|
||||||
/// Service account credentials (if configured)
|
/// Service account credentials (if configured)
|
||||||
static ref SERVICE_ACCOUNT_CREDENTIALS: Option<Credentials> =
|
static ref SERVICE_ACCOUNT_CREDENTIALS: Option<Credentials> =
|
||||||
|
@ -121,20 +116,10 @@ lazy_static! {
|
||||||
.and_then(|path| File::open(path).ok())
|
.and_then(|path| File::open(path).ok())
|
||||||
.and_then(|file| serde_json::from_reader(file).ok());
|
.and_then(|file| serde_json::from_reader(file).ok());
|
||||||
|
|
||||||
/// Descriptor of the currently monitored instance.
|
/// Descriptor of the currently monitored instance. Refer to the
|
||||||
///
|
/// documentation of `determine_monitored_resource` for more
|
||||||
/// For GCE instances, this will be the GCE instance ID. For
|
/// information.
|
||||||
/// non-GCE machines a sensible solution may be using the machine
|
static ref MONITORED_RESOURCE: Value = determine_monitored_resource();
|
||||||
/// 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(),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/// Path to the file in which journaldriver should persist its
|
/// Path to the file in which journaldriver should persist its
|
||||||
/// cursor state.
|
/// cursor state.
|
||||||
|
@ -153,6 +138,47 @@ fn get_metadata(url: &str) -> Result<String> {
|
||||||
Ok(output.trim().into())
|
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
|
/// Represents the response returned by the metadata server's token
|
||||||
/// endpoint. The token is normally valid for an hour.
|
/// endpoint. The token is normally valid for an hour.
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -456,7 +482,7 @@ fn flush(client: &Client,
|
||||||
/// https://cloud.google.com/logging/docs/reference/v2/rest/v2/entries/write
|
/// https://cloud.google.com/logging/docs/reference/v2/rest/v2/entries/write
|
||||||
fn prepare_request(entries: &[LogEntry]) -> Value {
|
fn prepare_request(entries: &[LogEntry]) -> Value {
|
||||||
json!({
|
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,
|
"resource": &*MONITORED_RESOURCE,
|
||||||
"entries": entries,
|
"entries": entries,
|
||||||
"partialSuccess": true
|
"partialSuccess": true
|
||||||
|
|
Loading…
Reference in a new issue