tracing_layer_slack/
lib.rs1#![doc = include_str!("../README.md")]
2
3pub use tracing_layer_core::BackgroundWorker;
4pub use tracing_layer_core::layer::WebhookLayer;
5pub use tracing_layer_core::filters::EventFilters;
6use serde::Serialize;
7use tracing_layer_core::layer::WebhookLayerBuilder;
8use tracing_layer_core::{Config, WebhookMessage, WebhookMessageFactory, WebhookMessageInputs};
9
10pub struct SlackLayer;
12
13impl SlackLayer {
14 pub fn builder(app_name: String, target_filters: EventFilters) -> WebhookLayerBuilder<SlackConfig, Self> {
15 WebhookLayer::builder(app_name, target_filters)
16 }
17}
18
19impl WebhookMessageFactory for SlackLayer {
20 fn create(inputs: WebhookMessageInputs) -> impl WebhookMessage {
21 let target = inputs.target;
22 let span = inputs.span;
23 let metadata = inputs.metadata;
24 let message = inputs.message;
25 let app_name = inputs.app_name;
26 let source_file = inputs.source_file;
27 let source_line = inputs.source_line;
28 let event_level = inputs.event_level;
29
30 #[cfg(feature = "blocks")]
31 {
32 let event_level_emoji = match event_level {
33 tracing::Level::TRACE => ":mag:",
34 tracing::Level::DEBUG => ":bug:",
35 tracing::Level::INFO => ":information_source:",
36 tracing::Level::WARN => ":warning:",
37 tracing::Level::ERROR => ":x:",
38 };
39 let blocks = serde_json::json!([
40 {
41 "type": "context",
42 "elements": [
43 {
44 "type": "mrkdwn",
45 "text": format!("{} - {} *{}*", app_name, event_level_emoji, event_level),
46 }
47 ]
48 },
49 {
50 "type": "section",
51 "text": {
52 "type": "mrkdwn",
53 "text": format!("\"_{}_\"", message),
54 }
55 },
56 {
57 "type": "section",
58 "fields": [
59 {
60 "type": "mrkdwn",
61 "text": format!("*Target Span*\n{}::{}", target, span)
62 },
63 {
64 "type": "mrkdwn",
65 "text": format!("*Source*\n{}#L{}", source_file, source_line)
66 }
67 ]
68 },
69 {
70 "type": "section",
71 "text": {
72 "type": "mrkdwn",
73 "text": "*Metadata:*"
74 }
75 },
76 {
77 "type": "section",
78 "text": {
79 "type": "mrkdwn",
80 "text": format!("```\n{}\n```", metadata)
81 }
82 }
83 ]);
84 let blocks_json = blocks.to_string();
85 SlackMessagePayload {
86 text: None,
87 blocks: Some(blocks_json),
88 webhook_url: inputs.webhook_url.to_string(),
89 }
90 }
91 #[cfg(not(feature = "blocks"))]
92 {
93 let event_level = event.metadata().level().as_str();
94 let source_file = event.metadata().file().unwrap_or("Unknown");
95 let source_line = event.metadata().line().unwrap_or(0);
96 let payload = format!(
97 concat!(
98 "*Trace from {}*\n",
99 "*Event [{}]*: \"{}\"\n",
100 "*Target*: _{}_\n",
101 "*Span*: _{}_\n",
102 "*Metadata*:\n",
103 "```",
104 "{}",
105 "```\n",
106 "*Source*: _{}#L{}_",
107 ),
108 app_name, event_level, message, span, target, metadata, source_file, source_line,
109 );
110 SlackMessagePayload {
111 text: Some(payload),
112 blocks: None,
113 webhook_url: webhook_url.to_string(),
114 }
115 }
116 }
117}
118
119#[derive(Debug, Clone, Serialize)]
122pub(crate) struct SlackMessagePayload {
123 #[serde(skip_serializing_if = "Option::is_none")]
124 text: Option<String>,
125 #[serde(skip_serializing_if = "Option::is_none")]
126 blocks: Option<String>,
127 #[serde(skip_serializing)]
128 webhook_url: String,
129}
130
131impl WebhookMessage for SlackMessagePayload {
132 fn webhook_url(&self) -> &str {
133 self.webhook_url.as_str()
134 }
135
136 fn serialize(&self) -> String {
137 serde_json::to_string(self).expect("failed to serialize slack message")
138 }
139}
140
141pub struct SlackConfig {
143 pub(crate) webhook_url: String,
144}
145
146impl SlackConfig {
147 pub fn new(webhook_url: String) -> Self {
148 Self { webhook_url }
149 }
150
151 pub fn new_from_env() -> Self {
157 Self::new(std::env::var("SLACK_WEBHOOK_URL").expect("slack webhook url in env"))
158 }
159}
160
161impl Default for SlackConfig {
162 fn default() -> Self {
163 Self::new_from_env()
164 }
165}
166
167impl Config for SlackConfig {
168 fn webhook_url(&self) -> &str {
169 &self.webhook_url
170 }
171
172 fn new_from_env() -> Self where Self: Sized {
173 Self::new_from_env()
174 }
175}
176
177#[cfg(test)]
178mod tests {
179
180}