use std::collections::HashMap;
use crossbeam_channel::Receiver;
use log::info;
use serde_json::Value;
use crate::errors::Result;
use crate::fields::FieldHolder;
use crate::response::Response;
use crate::sender::Sender;
use crate::Event;
use crate::{Builder, DynamicFieldFunc};
const DEFAULT_API_HOST: &str = "https://api.honeycomb.io";
const DEFAULT_API_KEY: &str = "";
const DEFAULT_DATASET: &str = "librust-dataset";
const DEFAULT_SAMPLE_RATE: usize = 1;
#[derive(Debug, Clone)]
pub struct Options {
pub api_key: String,
pub api_host: String,
pub dataset: String,
pub sample_rate: usize,
}
impl Default for Options {
fn default() -> Self {
Self {
api_key: DEFAULT_API_KEY.to_string(),
dataset: DEFAULT_DATASET.to_string(),
api_host: DEFAULT_API_HOST.to_string(),
sample_rate: DEFAULT_SAMPLE_RATE,
}
}
}
#[derive(Debug, Clone)]
pub struct Client<T: Sender> {
pub(crate) options: Options,
pub transmission: T,
builder: Builder,
}
impl<T> Client<T>
where
T: Sender,
{
pub fn new(options: Options, transmission: T) -> Self {
info!("Creating honey client");
let mut c = Self {
transmission,
options: options.clone(),
builder: Builder::new(options),
};
c.start();
c
}
fn start(&mut self) {
self.transmission.start();
}
pub fn add(&mut self, data: HashMap<String, Value>) {
self.builder.add(data);
}
pub fn add_field(&mut self, name: &str, value: Value) {
self.builder.add_field(name, value);
}
pub fn add_dynamic_field(&mut self, name: &str, func: DynamicFieldFunc) {
self.builder.add_dynamic_field(name, func);
}
pub fn close(mut self) -> Result<()> {
info!("closing libhoney client");
self.transmission.stop()
}
pub fn flush(&mut self) -> Result<()> {
info!("flushing libhoney client");
self.transmission.stop()?;
self.transmission.start();
Ok(())
}
pub fn new_builder(&self) -> Builder {
self.builder.clone()
}
pub fn new_event(&self) -> Event {
self.builder.new_event()
}
pub fn responses(&self) -> Receiver<Response> {
self.transmission.responses()
}
}
#[cfg(test)]
mod tests {
use super::{Client, FieldHolder, Options, Value};
use crate::transmission::{self, Transmission};
#[test]
fn test_init() {
let client = Client::new(
Options::default(),
Transmission::new(transmission::Options::default()).unwrap(),
);
client.close().unwrap();
}
#[test]
fn test_flush() {
use reqwest::StatusCode;
use serde_json::json;
let api_host = &mockito::server_url();
let _m = mockito::mock(
"POST",
mockito::Matcher::Regex(r"/1/batch/(.*)$".to_string()),
)
.with_status(200)
.with_header("content-type", "application/json")
.with_body("[{ \"status\": 202 }]")
.create();
let mut client = Client::new(
Options {
api_key: "some api key".to_string(),
api_host: api_host.to_string(),
..Options::default()
},
Transmission::new(transmission::Options::default()).unwrap(),
);
let mut event = client.new_event();
event.add_field("some_field", Value::String("some_value".to_string()));
event.metadata = Some(json!("some metadata in a string"));
event.send(&mut client).unwrap();
let response = client.responses().iter().next().unwrap();
assert_eq!(response.status_code, Some(StatusCode::ACCEPTED));
assert_eq!(response.metadata, Some(json!("some metadata in a string")));
client.flush().unwrap();
event = client.new_event();
event.add_field("some_field", Value::String("some_value".to_string()));
event.metadata = Some(json!("some metadata in a string"));
event.send(&mut client).unwrap();
let response = client.responses().iter().next().unwrap();
assert_eq!(response.status_code, Some(StatusCode::ACCEPTED));
assert_eq!(response.metadata, Some(json!("some metadata in a string")));
client.close().unwrap();
}
#[test]
fn test_send_without_api_key() {
use serde_json::json;
use crate::errors::ErrorKind;
let api_host = &mockito::server_url();
let _m = mockito::mock(
"POST",
mockito::Matcher::Regex(r"/1/batch/(.*)$".to_string()),
)
.with_status(200)
.with_header("content-type", "application/json")
.with_body("[{ \"status\": 202 }]")
.create();
let mut client = Client::new(
Options {
api_host: api_host.to_string(),
..Options::default()
},
Transmission::new(transmission::Options::default()).unwrap(),
);
let mut event = client.new_event();
event.add_field("some_field", Value::String("some_value".to_string()));
event.metadata = Some(json!("some metadata in a string"));
let err = event.send(&mut client).err().unwrap();
assert_eq!(err.kind, ErrorKind::MissingOption);
assert_eq!(
err.message,
"missing option 'api_key', can't send to Honeycomb"
);
client.close().unwrap();
}
}