add newrelic logging capability

This commit is contained in:
Brandon Thomas
2020-08-04 22:26:30 -04:00
parent aeb905357e
commit 6bd56aad75
4 changed files with 82 additions and 6 deletions
Generated
+17
View File
@@ -420,6 +420,22 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "newrelic"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7ec1eb312ccd33c2d88ff317d59164465a41014ad465ba8a67e2c062343e3a8"
dependencies = [
"log",
"newrelic-sys",
]
[[package]]
name = "newrelic-sys"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a9b9030b5f433ac2afb956eeaf89020e07d3cb9b0561cd07f1737c97a4af93a"
[[package]] [[package]]
name = "num_cpus" name = "num_cpus"
version = "1.13.0" version = "1.13.0"
@@ -835,6 +851,7 @@ dependencies = [
"hyper", "hyper",
"hyper-reverse-proxy", "hyper-reverse-proxy",
"log", "log",
"newrelic",
"rand", "rand",
"serde", "serde",
"serde_derive", "serde_derive",
+1
View File
@@ -19,6 +19,7 @@ futures = "0.1"
hyper = "0.12" hyper = "0.12"
hyper-reverse-proxy = "0.4" hyper-reverse-proxy = "0.4"
log = "0.4.8" log = "0.4.8"
newrelic = "0.2.2"
rand = "0.7.3" rand = "0.7.3"
serde = "1.0.104" serde = "1.0.104"
serde_derive = "1.0.104" serde_derive = "1.0.104"
+28 -6
View File
@@ -2,6 +2,8 @@
#[macro_use] extern crate log; #[macro_use] extern crate log;
#[macro_use] extern crate serde_derive; #[macro_use] extern crate serde_derive;
pub mod newrelic_logger;
use anyhow::Result as AnyhowResult; use anyhow::Result as AnyhowResult;
use futures::future::{self, Future}; use futures::future::{self, Future};
use hyper::Method; use hyper::Method;
@@ -19,18 +21,22 @@ use std::sync::Arc;
use rand::seq::IteratorRandom; use rand::seq::IteratorRandom;
use hyper::http::header::HeaderName; use hyper::http::header::HeaderName;
use hyper::header::HeaderValue; use hyper::header::HeaderValue;
use newrelic::App;
use crate::newrelic_logger::NewRelicLogger;
type BoxFut = Box<dyn Future<Item=Response<Body>, Error=hyper::Error> + Send>; type BoxFut = Box<dyn Future<Item=Response<Body>, Error=hyper::Error> + Send>;
const ENV_DEFAULT_ROUTE : &'static str = "DEFAULT_ROUTE"; const ENV_DEFAULT_ROUTE : &'static str = "DEFAULT_ROUTE";
const ENV_NEWRELIC_API_KEY : &'static str = "NEWRELIC_API_KEY";
const ENV_PROXY_CONFIG_FILE : &'static str = "PROXY_CONFIG_FILE"; const ENV_PROXY_CONFIG_FILE : &'static str = "PROXY_CONFIG_FILE";
const ENV_RUST_LOG : &'static str = "RUST_LOG"; const ENV_RUST_LOG : &'static str = "RUST_LOG";
const ENV_SERVICE_PORT : &'static str = "SERVICE_PORT"; const ENV_SERVICE_PORT : &'static str = "SERVICE_PORT";
const DEFAULT_DEFAULT_ROUTE : &'static str = "http://127.0.0.1:12345"; const DEFAULT_DEFAULT_ROUTE : &'static str = "http://127.0.0.1:12345";
const DEFAULT_NEWRELIC_API_KEY : &'static str = "";
const DEFAULT_PROXY_CONFIG_FILE : &'static str = "proxy_configs.toml"; const DEFAULT_PROXY_CONFIG_FILE : &'static str = "proxy_configs.toml";
const DEFAULT_RUST_LOG: &'static str = "tokio_reactor=warn,hyper=info,debug"; const DEFAULT_RUST_LOG : &'static str = "tokio_reactor=warn,hyper=info,debug";
const DEFAULT_SERVICE_PORT: u16 = 5555; const DEFAULT_SERVICE_PORT : u16 = 5555;
#[derive(Deserialize, Debug, Clone)] #[derive(Deserialize, Debug, Clone)]
struct ProxyConfigs { struct ProxyConfigs {
@@ -198,6 +204,7 @@ fn main() -> AnyhowResult<()> {
let default_route = get_env_string(ENV_DEFAULT_ROUTE, DEFAULT_DEFAULT_ROUTE); let default_route = get_env_string(ENV_DEFAULT_ROUTE, DEFAULT_DEFAULT_ROUTE);
let service_port = get_env_num::<u16>(ENV_SERVICE_PORT, DEFAULT_SERVICE_PORT)?; let service_port = get_env_num::<u16>(ENV_SERVICE_PORT, DEFAULT_SERVICE_PORT)?;
let newrelic_api_key = get_env_string(ENV_NEWRELIC_API_KEY, DEFAULT_NEWRELIC_API_KEY);
info!("Default route: {}", default_route); info!("Default route: {}", default_route);
@@ -219,23 +226,38 @@ fn main() -> AnyhowResult<()> {
default_route: default_route, default_route: default_route,
}); });
let newrelic_logger = if newrelic_api_key.is_empty() {
NewRelicLogger::null_instance()
} else {
NewRelicLogger::try_new_or_null("voder-proxy", &newrelic_api_key)
};
let newrelic_logger = Arc::new(newrelic_logger);
let make_service = make_service_fn(move |socket: &AddrStream| { let make_service = make_service_fn(move |socket: &AddrStream| {
let remote_addr = socket.remote_addr(); let remote_addr = socket.remote_addr();
info!("Got a request from: {:?}", remote_addr); info!("Got a request from: {:?}", remote_addr);
let router2 = router.clone(); let router2 = router.clone();
let newrelic_logger2 = newrelic_logger.clone();
service_fn(move |req: Request<Body>| { service_fn(move |req: Request<Body>| {
let router3 = router2.clone(); let router3 = router2.clone();
let newrelic_logger3 = newrelic_logger2.clone();
match (req.method(), req.uri().path()) { match (req.method(), req.uri().path()) {
(&Method::POST, "/speak") => (&Method::POST, "/speak") => {
speak_proxy(req, remote_addr.clone(), router3, "/speak"), let _droppable_transaction = newrelic_logger3.web_transaction("proxy /speak");
(&Method::POST, "/speak_spectrogram") => speak_proxy(req, remote_addr.clone(), router3, "/speak")
speak_proxy(req, remote_addr.clone(), router3, "/speak_spectrogram"), },
(&Method::POST, "/speak_spectrogram") => {
let _droppable_transaction = newrelic_logger3.web_transaction("proxy /speak_spectrogram");
speak_proxy(req, remote_addr.clone(), router3, "/speak_spectrogram")
},
(&Method::GET, "/proxy_health") => (&Method::GET, "/proxy_health") =>
health_check_response(req), health_check_response(req),
_ => { _ => {
let _droppable_transaction = newrelic_logger3.web_transaction("unmatched endpoint");
let forward = router3.get_random_host(); let forward = router3.get_random_host();
info!("Forwarding to `{}` random host: {}", &forward, req.uri()); info!("Forwarding to `{}` random host: {}", &forward, req.uri());
hyper_reverse_proxy::call(remote_addr.ip(), &forward, req) hyper_reverse_proxy::call(remote_addr.ip(), &forward, req)
+36
View File
@@ -0,0 +1,36 @@
use anyhow::Result as AnyhowResult;
use newrelic::{App, Transaction};
pub struct NewRelicLogger {
newrelic_api: Option<App>,
}
impl NewRelicLogger {
pub fn new(app_name: &str, api_key: &str) -> AnyhowResult<Self> {
let newrelic_api = App::new(app_name, api_key)?;
Ok(Self {
newrelic_api: Some(newrelic_api),
})
}
pub fn null_instance() -> Self {
Self {
newrelic_api: None,
}
}
pub fn try_new_or_null(app_name: &str, api_key: &str) -> Self {
match Self::new(app_name, api_key) {
Ok(instance) => instance,
Err(_) => Self::null_instance(),
}
}
pub fn web_transaction(&self, transaction_name: &str) -> Option<Transaction> {
if let Some(ref newrelic_api) = self.newrelic_api {
info!("Logging request to NewRelic");
return newrelic_api.web_transaction(transaction_name).ok();
}
None
}
}