This gist outlines the steps for sending data collected with the tracing crate, a Rust crate for application-level tracing, to a Fastly log endpoint. For simplicity, I will use the Subscriber and Layer implementations included in the tracing_subscriber
crate. However, you can write your own custom implementations to modify the collected data and its format.
Add the required dependencies to your Cargo.toml file.
tracing = "0.1.37"
tracing-subscriber = { version = "0.3.17", features = ["json"] }
Write a MakeWriter implementation to send logs to a Fastly logging endpoint. Below is a simple example. Save the code in a file named log_writer.rs
.
use std::io::Write;
use fastly::log::Endpoint;
use tracing_subscriber::fmt::MakeWriter;
pub struct FastlyLogWriter {
endpoint: Endpoint
}
impl FastlyLogWriter {
pub fn new(endpoint: &str) -> Self {
FastlyLogWriter { endpoint: Endpoint::from_name(endpoint) }
}
}
impl MakeWriter<'_> for FastlyLogWriter {
type Writer = FastlyLogWriter;
fn make_writer(&self) -> Self::Writer {
FastlyLogWriter { endpoint: self.endpoint.clone() }
}
}
impl Write for FastlyLogWriter {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
// Collapse the formatting of the message into a String, so that we only call the
// underlying `write` once. This prevents the message from being split into multiple
// lines in surprising ways, depending on how the format arguments are structured.
let msg = format!("{}", String::from_utf8_lossy(buf));
write!(self.endpoint.clone(), "{}", msg)?;
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
Create a Layer using the tracing_subscriber::fmt
and initialize a Subscriber with that Layer. Here, we are using a log endpoint named my_endpoint
.
use fastly::http::StatusCode;
use fastly::{Error, Request, Response};
use tracing::instrument;
use tracing_subscriber::prelude::*;
use tracing_subscriber::Registry;
mod log_writer;
use log_writer::FastlyLogWriter;
#[fastly::main]
fn main(_req: Request) -> Result<Response, Error> {
// MakeWriter implementation to send logs to a Fastly logging endpoint.
let writer = FastlyLogWriter::new("my_endpoint");
// Build a layer from tracing_subscriber::fmt.
// This layer will format the traced data as JSON before it is sent to the Fastly log endpoint.
let json_export_layer = tracing_subscriber::fmt::layer()
.with_writer(writer)
.json();
// Add the layer to the Subscriber and initialize it.
Registry::default()
.with(json_export_layer)
.init();
some_task();
Ok(Response::from_status(StatusCode::OK))
}
#[instrument]
fn some_task() {
tracing::info!("yo!");
}
fastly compute publish
Add a log endpoint to your Fastly service. In this example, I'm using Papertrail.
fastly service-version clone --version=latest
fastly logging papertrail create --version=latest --placement=none --name=my_endpoint --address=xxx.papertrailapp.com --port=xxxxx
fastly service-version activate --version=latest