azure_functions/
context.rs1use std::{cell::RefCell, env, path::PathBuf};
3
4pub(crate) const UNKNOWN_FUNCTION: &str = "<unknown>";
5
6thread_local!(pub(crate) static CURRENT: RefCell<Context> = RefCell::new(
7 Context{
8 invocation_id: String::new(),
9 function_id: String::new(),
10 function_name: UNKNOWN_FUNCTION
11 }
12));
13
14#[derive(Debug, Clone)]
16pub struct Context {
17 pub(crate) invocation_id: String,
18 pub(crate) function_id: String,
19 pub(crate) function_name: &'static str,
20}
21
22pub(crate) struct ContextGuard;
23
24impl Drop for ContextGuard {
25 fn drop(&mut self) {
26 Context::clear();
27 }
28}
29
30impl Context {
31 pub fn current() -> Option<Self> {
35 let mut current = None;
36
37 CURRENT.with(|c| {
38 let c = c.borrow();
39 if !c.invocation_id.is_empty() {
40 current = Some(c.clone());
41 }
42 });
43
44 current
45 }
46
47 #[must_use]
48 pub(crate) fn set(
49 invocation_id: &str,
50 function_id: &str,
51 function_name: &'static str,
52 ) -> ContextGuard {
53 CURRENT.with(|c| {
54 let mut c = c.borrow_mut();
55 c.invocation_id.replace_range(.., invocation_id);
56 c.function_id.replace_range(.., function_id);
57 c.function_name = function_name;
58 });
59
60 ContextGuard {}
61 }
62
63 pub(crate) fn clear() {
64 CURRENT.with(|c| {
65 let mut c = c.borrow_mut();
66 c.invocation_id.clear();
67 c.function_id.clear();
68 c.function_name = UNKNOWN_FUNCTION;
69 });
70 }
71
72 pub fn invocation_id(&self) -> &str {
74 &self.invocation_id
75 }
76
77 pub fn function_id(&self) -> &str {
79 &self.function_id
80 }
81
82 pub fn function_name(&self) -> &str {
84 self.function_name
85 }
86
87 pub fn function_directory(&self) -> Option<PathBuf> {
89 self.app_directory().map(|p| p.join(self.function_name))
90 }
91
92 pub fn app_directory(&self) -> Option<PathBuf> {
94 env::current_exe()
95 .map(|p| p.parent().map(ToOwned::to_owned))
96 .ok()
97 .unwrap_or(None)
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104
105 #[test]
106 fn it_returns_none_without_context() {
107 assert_eq!(Context::current().is_none(), true);
108 }
109
110 #[test]
111 fn it_returns_current_context() {
112 let _guard = Context::set("1234", "5678", "foo");
113
114 let context = Context::current().unwrap();
115
116 assert_eq!(context.invocation_id(), "1234");
117 assert_eq!(context.function_id(), "5678");
118 assert_eq!(context.function_name(), "foo");
119 }
120}