summaryrefslogtreecommitdiffstats
path: root/rust/src
diff options
context:
space:
mode:
Diffstat (limited to 'rust/src')
-rw-r--r--rust/src/bin/fatcatd.rs29
-rw-r--r--rust/src/endpoints.rs55
-rw-r--r--rust/src/server.rs12
3 files changed, 76 insertions, 20 deletions
diff --git a/rust/src/bin/fatcatd.rs b/rust/src/bin/fatcatd.rs
index 388c6e61..df5c390e 100644
--- a/rust/src/bin/fatcatd.rs
+++ b/rust/src/bin/fatcatd.rs
@@ -15,6 +15,9 @@ use iron_slog::{DefaultLogFormatter, LoggerMiddleware};
use sentry::integrations::panic;
use slog::{Drain, Logger};
use std::env;
+use cadence::{StatsdClient, QueuingMetricSink, BufferedUdpMetricSink};
+use cadence::prelude::*;
+use std::net::UdpSocket;
// HTTP header middleware
header! { (XClacksOverhead, "X-Clacks-Overhead") => [String] }
@@ -29,6 +32,7 @@ impl AfterMiddleware for XClacksOverheadMiddleware {
}
}
+
/// Create custom server, wire it to the autogenerated router,
/// and pass it to the web server.
fn main() -> Result<()> {
@@ -60,7 +64,30 @@ fn main() -> Result<()> {
None
};
- let server = create_server()?;
+ let mut server = create_server()?;
+
+ // metrics reporting
+ match env::var("FATCAT_STATSD_HOST") {
+ Err(_) => {
+ info!(logger, "no metrics recipient configured");
+ },
+ Ok(host) => {
+ let port: u16 = match env::var("FATCAT_STATSD_PORT") {
+ Err(_) => cadence::DEFAULT_PORT,
+ Ok(var) => var.parse::<u16>()?, // "expect FATCAT_STATSD_PORT to be null or an integer
+ };
+ let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
+ socket.set_nonblocking(true).unwrap();
+ let udp_sink = BufferedUdpMetricSink::from((host.as_ref(), port), socket).unwrap();
+ let queuing_sink = QueuingMetricSink::from(udp_sink);
+ info!(logger, "sending statsd metrics via UDP to: {}:{}", host, port);
+ server.metrics = StatsdClient::from_sink("fatcat.api", queuing_sink);
+ //server.metrics = StatsdClient::from_udp_host("fatcat.api", (host.as_ref(), port))?;
+ server.metrics.incr("restart").unwrap();
+ }
+ };
+ info!(logger, "{:#?}", server.metrics);
+
info!(
logger,
"using primary auth key: {}", server.auth_confectionary.identifier,
diff --git a/rust/src/endpoints.rs b/rust/src/endpoints.rs
index 1bed3c56..027e25bc 100644
--- a/rust/src/endpoints.rs
+++ b/rust/src/endpoints.rs
@@ -22,6 +22,7 @@ use futures::{self, Future};
use sentry::integrations::failure::capture_fail;
use std::str::FromStr;
use uuid::{self, Uuid};
+use cadence::prelude::*;
// This makes response matching below *much* more terse
use crate::errors::FatcatError::*;
@@ -121,8 +122,10 @@ macro_rules! wrap_entity_handlers {
edit_context.check(&conn)?;
entity.db_create(&conn, &edit_context)?.into_model()
}).map_err(|e| FatcatError::from(e)) {
- Ok(edit) =>
- $post_resp::CreatedEntity(edit),
+ Ok(edit) => {
+ self.metrics.incr("entities.created").ok();
+ $post_resp::CreatedEntity(edit)
+ },
Err(fe) => generic_auth_err_responses!(fe, $post_resp),
};
Box::new(futures::done(Ok(ret)))
@@ -146,8 +149,14 @@ macro_rules! wrap_entity_handlers {
} else { None };
self.$post_batch_handler(&conn, entity_list, autoaccept.unwrap_or(false), auth_context.editor_id, editgroup_id)
}).map_err(|e| FatcatError::from(e)) {
- Ok(edit) =>
- $post_batch_resp::CreatedEntities(edit),
+ Ok(edits) => {
+ self.metrics.count("entities.created", edits.len() as i64).ok();
+ if let Some(true) = autoaccept {
+ self.metrics.incr("editgroup.created").ok();
+ self.metrics.incr("editgroup.accepted").ok();
+ };
+ $post_batch_resp::CreatedEntities(edits)
+ },
Err(fe) => generic_auth_err_responses!(fe, $post_batch_resp),
};
Box::new(futures::done(Ok(ret)))
@@ -171,8 +180,10 @@ macro_rules! wrap_entity_handlers {
edit_context.check(&conn)?;
entity.db_update(&conn, &edit_context, entity_id)?.into_model()
}).map_err(|e| FatcatError::from(e)) {
- Ok(edit) =>
- $update_resp::UpdatedEntity(edit),
+ Ok(edit) => {
+ self.metrics.incr("entities.updated").ok();
+ $update_resp::UpdatedEntity(edit)
+ },
Err(fe) => generic_auth_err_responses!(fe, $update_resp),
};
Box::new(futures::done(Ok(ret)))
@@ -195,8 +206,10 @@ macro_rules! wrap_entity_handlers {
edit_context.check(&conn)?;
$model::db_delete(&conn, &edit_context, entity_id)?.into_model()
}).map_err(|e| FatcatError::from(e)) {
- Ok(edit) =>
- $delete_resp::DeletedEntity(edit),
+ Ok(edit) => {
+ self.metrics.incr("entities.deleted").ok();
+ $delete_resp::DeletedEntity(edit)
+ },
Err(fe) => generic_auth_err_responses!(fe, $delete_resp),
};
Box::new(futures::done(Ok(ret)))
@@ -745,10 +758,13 @@ impl Api for Server {
})
.map_err(|e| FatcatError::from(e))
{
- Ok(()) => AcceptEditgroupResponse::MergedSuccessfully(Success {
- success: true,
- message: "horray!".to_string(),
- }),
+ Ok(()) => {
+ self.metrics.incr("editgroup.accepted").ok();
+ AcceptEditgroupResponse::MergedSuccessfully(Success {
+ success: true,
+ message: "horray!".to_string(),
+ })
+ },
Err(fe) => generic_auth_err_responses!(fe, AcceptEditgroupResponse),
};
Box::new(futures::done(Ok(ret)))
@@ -804,7 +820,10 @@ impl Api for Server {
})
.map_err(|e| FatcatError::from(e))
{
- Ok(eg) => CreateEditgroupResponse::SuccessfullyCreated(eg),
+ Ok(eg) => {
+ self.metrics.incr("editgroup.created").ok();
+ CreateEditgroupResponse::SuccessfullyCreated(eg)
+ },
Err(fe) => match fe {
NotFound(_, _) => CreateEditgroupResponse::NotFound(fe.into()),
DatabaseError(_) | InternalError(_) => {
@@ -884,8 +903,14 @@ impl Api for Server {
})
.map_err(|e: Error| FatcatError::from(e))
{
- Ok((result, true)) => AuthOidcResponse::Created(result),
- Ok((result, false)) => AuthOidcResponse::Found(result),
+ Ok((result, true)) => {
+ self.metrics.incr("account.signup").ok();
+ AuthOidcResponse::Created(result)
+ },
+ Ok((result, false)) => {
+ self.metrics.incr("account.login").ok();
+ AuthOidcResponse::Found(result)
+ },
Err(fe) => match fe {
DatabaseError(_) | InternalError(_) => {
error!("{}", fe);
diff --git a/rust/src/server.rs b/rust/src/server.rs
index 6b389a97..66b215fc 100644
--- a/rust/src/server.rs
+++ b/rust/src/server.rs
@@ -8,6 +8,7 @@ use diesel::pg::PgConnection;
use diesel::r2d2::ConnectionManager;
use dotenv::dotenv;
use std::env;
+use cadence::{StatsdClient, NopMetricSink};
#[cfg(feature = "postgres")]
embed_migrations!("../migrations/");
@@ -32,6 +33,7 @@ pub fn database_worker_pool() -> Result<ConnectionPool> {
pub struct Server {
pub db_pool: ConnectionPool,
pub auth_confectionary: AuthConfectionary,
+ pub metrics: StatsdClient,
}
/// Instantiate a new API server with a pooled database connection
@@ -39,13 +41,15 @@ pub fn create_server() -> Result<Server> {
dotenv().ok();
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
let manager = ConnectionManager::<PgConnection>::new(database_url);
- let pool = diesel::r2d2::Pool::builder()
+ let db_pool = diesel::r2d2::Pool::builder()
.build(manager)
.expect("Failed to create database pool.");
- let confectionary = env_confectionary()?;
+ let auth_confectionary = env_confectionary()?;
+ let metrics = StatsdClient::from_sink("blackhole", NopMetricSink);
Ok(Server {
- db_pool: pool,
- auth_confectionary: confectionary,
+ db_pool,
+ auth_confectionary,
+ metrics,
})
}