You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@teaclave.apache.org by hs...@apache.org on 2023/03/07 05:29:26 UTC

[incubator-teaclave] 03/03: Add teaclave logger

This is an automated email from the ASF dual-hosted git repository.

hsun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-teaclave.git

commit 27cf49bb765ae6fb68ca8c4eb388798e85d14e48
Author: sunhe05 <su...@baidu.com>
AuthorDate: Fri Mar 3 03:44:24 2023 +0000

    Add teaclave logger
---
 cmake/tomls/Cargo.sgx_trusted_lib.lock             |  65 +++++----
 examples/rust/builtin_echo/src/main.rs             |   2 +-
 .../rust/builtin_ordered_set_intersect/src/main.rs |  18 ++-
 function/src/echo.rs                               |   6 +
 function/src/ordered_set_intersect.rs              |   3 +
 .../service_enclave_utils => logger}/Cargo.toml    |  39 +++--
 logger/README.md                                   |  19 +++
 logger/src/lib.rs                                  | 161 +++++++++++++++++++++
 logger/src/task_logger.rs                          |  62 ++++++++
 sdk/rust/src/bindings.rs                           |   2 +-
 sdk/rust/src/lib.rs                                |   9 +-
 services/execution/enclave/Cargo.toml              |   2 +-
 services/execution/enclave/src/lib.rs              |   2 +
 services/execution/enclave/src/service.rs          |  23 ++-
 services/proto/src/proto/teaclave_common.proto     |   1 +
 services/proto/src/teaclave_common.rs              |   2 +
 services/utils/service_enclave_utils/Cargo.toml    |  15 +-
 services/utils/service_enclave_utils/src/lib.rs    |  31 ++--
 tests/functional/enclave/src/execution_service.rs  |  11 +-
 tests/functional/enclave/src/scheduler_service.rs  |   2 +-
 tests/unit/enclave/Cargo.toml                      |   3 +
 tests/unit/enclave/src/lib.rs                      |   1 +
 types/src/task.rs                                  |   8 +-
 23 files changed, 399 insertions(+), 88 deletions(-)

diff --git a/cmake/tomls/Cargo.sgx_trusted_lib.lock b/cmake/tomls/Cargo.sgx_trusted_lib.lock
index dc5c507f..6e9190cc 100644
--- a/cmake/tomls/Cargo.sgx_trusted_lib.lock
+++ b/cmake/tomls/Cargo.sgx_trusted_lib.lock
@@ -138,10 +138,7 @@ version = "0.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7"
 dependencies = [
- "humantime",
  "log",
- "regex",
- "termcolor",
 ]
 
 [[package]]
@@ -230,12 +227,6 @@ version = "1.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
 
-[[package]]
-name = "humantime"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
-
 [[package]]
 name = "idna"
 version = "0.3.0"
@@ -357,6 +348,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
 dependencies = [
  "cfg-if 1.0.0",
+ "value-bag",
 ]
 
 [[package]]
@@ -1001,6 +993,12 @@ version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
 
+[[package]]
+name = "sval"
+version = "1.0.0-alpha.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "45f6ee7c7b87caf59549e9fe45d6a69c75c8019e79e212a835c5da0e92f0ba08"
+
 [[package]]
 name = "syn"
 version = "0.15.44"
@@ -1322,6 +1320,17 @@ dependencies = [
  "thiserror",
 ]
 
+[[package]]
+name = "teaclave_logger"
+version = "0.4.0"
+dependencies = [
+ "anyhow",
+ "log",
+ "sgx_cov",
+ "sgx_types",
+ "teaclave_test_utils",
+]
+
 [[package]]
 name = "teaclave_management_service_enclave"
 version = "0.4.0"
@@ -1442,6 +1451,8 @@ dependencies = [
  "sgx_macros",
  "teaclave_attestation",
  "teaclave_config",
+ "teaclave_logger",
+ "teaclave_proto",
  "teaclave_rpc",
  "teaclave_service_enclave_utils_proc_macro",
  "teaclave_types",
@@ -1552,6 +1563,7 @@ dependencies = [
  "teaclave_executor_context",
  "teaclave_frontend_service_enclave",
  "teaclave_function",
+ "teaclave_logger",
  "teaclave_management_service_enclave",
  "teaclave_rpc",
  "teaclave_runtime",
@@ -1580,15 +1592,6 @@ dependencies = [
  "thiserror",
 ]
 
-[[package]]
-name = "termcolor"
-version = "1.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
-dependencies = [
- "winapi-util",
-]
-
 [[package]]
 name = "thiserror"
 version = "1.0.38"
@@ -1698,6 +1701,23 @@ dependencies = [
  "sha1",
 ]
 
+[[package]]
+name = "value-bag"
+version = "1.0.0-alpha.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55"
+dependencies = [
+ "ctor",
+ "sval",
+ "version_check",
+]
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
 [[package]]
 name = "wasi"
 version = "0.10.2+wasi-snapshot-preview1"
@@ -1803,15 +1823,6 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 
-[[package]]
-name = "winapi-util"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
-dependencies = [
- "winapi",
-]
-
 [[package]]
 name = "winapi-x86_64-pc-windows-gnu"
 version = "0.4.0"
diff --git a/examples/rust/builtin_echo/src/main.rs b/examples/rust/builtin_echo/src/main.rs
index cedce10f..11e95a69 100644
--- a/examples/rust/builtin_echo/src/main.rs
+++ b/examples/rust/builtin_echo/src/main.rs
@@ -90,7 +90,7 @@ fn echo(message: &str) -> Result<Vec<u8>> {
 
     println!("[+] getting result");
     let response = client.get_task_result(&task_id)?;
-    Ok(response)
+    Ok(response.0)
 }
 
 fn main() -> Result<()> {
diff --git a/examples/rust/builtin_ordered_set_intersect/src/main.rs b/examples/rust/builtin_ordered_set_intersect/src/main.rs
index 83aa188c..636dcd04 100644
--- a/examples/rust/builtin_ordered_set_intersect/src/main.rs
+++ b/examples/rust/builtin_ordered_set_intersect/src/main.rs
@@ -118,7 +118,7 @@ impl Client {
             "Native Private Set Intersection.",
             "builtin",
             None,
-            Some(&["order"]),
+            Some(&["order", "save_log"]),
             Some(vec![
                 teaclave_client_sdk::FunctionInput::new("input_data1", "Client 0 data.", false),
                 teaclave_client_sdk::FunctionInput::new("input_data2", "Client 1 data.", false),
@@ -129,7 +129,7 @@ impl Client {
             ]),
         )?;
         self.client.get_function(&function_id)?;
-        let function_arguments = hashmap!("order" => "ascending"); // Order can be ascending or desending
+        let function_arguments = hashmap!("order" => "ascending", "save_log" => "true"); // Order can be ascending or desending
         let inputs_ownership = hashmap!(&self.user_data.input_label => vec![self.user_data.user_id.to_string()], &self.user_data.peer_input_label => vec![self.user_data.peer_id.to_string()]);
         let outputs_ownership = hashmap!(&self.user_data.output_label => vec![self.user_data.user_id.to_string()], &self.user_data.peer_output_label => vec![self.user_data.peer_id.to_string()]);
 
@@ -193,7 +193,7 @@ impl Client {
         Ok(())
     }
 
-    fn get_task_result(&mut self, task_id: &str) -> Result<Vec<u8>> {
+    fn get_task_result(&mut self, task_id: &str) -> Result<(Vec<u8>, Vec<String>)> {
         println!("[+] {} getting result", self.user_data.user_id);
         let response = self.client.get_task_result(&task_id)?;
         Ok(response)
@@ -260,11 +260,19 @@ fn main() -> Result<()> {
 
     let result_user0 = user0.get_task_result(&task_id)?;
 
-    println!("[+] User 0 result: {:?}", String::from_utf8(result_user0));
+    println!(
+        "[+] User 0 result: {:?} log: {:?} ",
+        String::from_utf8(result_user0.0),
+        result_user0.1
+    );
 
     let result_user1 = user1.get_task_result(&task_id)?;
 
-    println!("[+] User 1 result: {:?}", String::from_utf8(result_user1));
+    println!(
+        "[+] User 1 result: {:?} log {:?}",
+        String::from_utf8(result_user1.0),
+        result_user1.1
+    );
 
     println!("[+] done");
     Ok(())
diff --git a/function/src/echo.rs b/function/src/echo.rs
index 238b3184..a0c1de71 100644
--- a/function/src/echo.rs
+++ b/function/src/echo.rs
@@ -48,6 +48,12 @@ impl Echo {
         _runtime: FunctionRuntime,
     ) -> anyhow::Result<String> {
         let message = EchoArguments::try_from(arguments)?.message;
+
+        #[cfg(test_mode)]
+        log::info!("{}", message);
+        #[cfg(test_mode)]
+        log::debug!("{}", message);
+
         Ok(message)
     }
 }
diff --git a/function/src/ordered_set_intersect.rs b/function/src/ordered_set_intersect.rs
index 24ec98c4..32124111 100644
--- a/function/src/ordered_set_intersect.rs
+++ b/function/src/ordered_set_intersect.rs
@@ -87,6 +87,9 @@ impl OrderedSetIntersect {
         for item in result2 {
             write!(&mut output2, "{}", item as u32)?;
         }
+
+        log::trace!("{}", common_sets);
+
         Ok(format!("{} common items", common_sets))
     }
 }
diff --git a/services/utils/service_enclave_utils/Cargo.toml b/logger/Cargo.toml
similarity index 51%
copy from services/utils/service_enclave_utils/Cargo.toml
copy to logger/Cargo.toml
index 1d54e0b8..2184685c 100644
--- a/services/utils/service_enclave_utils/Cargo.toml
+++ b/logger/Cargo.toml
@@ -16,35 +16,30 @@
 # under the License.
 
 [package]
-name = "teaclave_service_enclave_utils"
+name = "teaclave_logger"
 version = "0.4.0"
 authors = ["Teaclave Contributors <de...@teaclave.apache.org>"]
-description = "Teaclave enclave utils"
+description = "Teaclave worker"
 license = "Apache-2.0"
 edition = "2021"
 
+[lib]
+name = "teaclave_logger"
+crate-type = ["staticlib", "rlib"]
+
 [features]
-default = []
-mesalock_sgx = [
-    "env_logger/termcolor",
-    "env_logger/humantime",
-    "env_logger/regex",
-    "teaclave_types/mesalock_sgx",
-    "teaclave_attestation/mesalock_sgx",
-    "teaclave_rpc/mesalock_sgx",
-]
-cov = ["sgx_cov", "sgx_macros"]
+default = ["mesalock_sgx"]
+mesalock_sgx = []
+cov = ["sgx_cov"]
+enclave_unit_test = ["teaclave_test_utils/mesalock_sgx"]
 
 [dependencies]
-anyhow     = { version = "1.0.26" }
-env_logger = { version = "0.9.3", default_features = false }
-log        = { version = "0.4.17", features = ["release_max_level_info"] }
+anyhow              = { version = "1.0.26" }
+log                 = { version = "0.4.17", features = ["release_max_level_info", "kv_unstable_std"] }
+
+teaclave_test_utils = { path = "../tests/utils", optional = true }
 
-teaclave_service_enclave_utils_proc_macro = { path = "./proc_macro" }
-teaclave_types       = { path = "../../../types" }
-teaclave_attestation = { path = "../../../attestation" }
-teaclave_rpc         = { path = "../../../rpc" }
-teaclave_config      = { path = "../../../config" }
+sgx_cov             = { version = "2.0.0", optional = true }
 
-sgx_cov  = { version = "2.0.0", optional = true }
-sgx_macros  = { version = "2.0.0", optional = true }
+[target.'cfg(not(target_vendor = "teaclave"))'.dependencies]
+sgx_types = { version = "2.0.0" }
diff --git a/logger/README.md b/logger/README.md
new file mode 100644
index 00000000..1ad404d0
--- /dev/null
+++ b/logger/README.md
@@ -0,0 +1,19 @@
+---
+permalink: /docs/codebase/logger
+---
+
+# Logger
+
+A logger for Teaclave services. It can collect logs to a buffer.
+Logs not saved to buffer can be logged by another logger that
+implements `log` trait.
+
+## Task logging
+
+When the logger is imported in the `execution service`, it can send the logs
+during a task to a buffer. The `kv_unstable` feature in the `log` crate is used
+to pass the pointer to the buffer to the logger. After the buffer is set, the
+logger will save logs to the buffer. The logger will drop the task logger after
+receiving a null pointer. Another logger which we call `secondary logger` will
+handle the logs coming afterwards if it is set. The logs before the task starts
+are sent to the secondary logger as well.
diff --git a/logger/src/lib.rs b/logger/src/lib.rs
new file mode 100644
index 00000000..dab63d90
--- /dev/null
+++ b/logger/src/lib.rs
@@ -0,0 +1,161 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#![feature(strict_provenance)]
+
+mod task_logger;
+use task_logger::TaskLogger;
+
+use std::sync::RwLock;
+
+use log::{LevelFilter, Log, Metadata, Record};
+
+struct TeaclaveLogger<T> {
+    task_logger: RwLock<Option<TaskLogger>>,
+    secondary_logger: Option<T>,
+}
+
+impl<T: Log> TeaclaveLogger<T> {
+    pub fn log_task(&self, task_logger: TaskLogger) {
+        let mut lock = self.task_logger.write().unwrap();
+        assert!(lock.is_none(), "only one task is allowed to be logged");
+
+        if let Some(sl) = &self.secondary_logger {
+            sl.flush()
+        }
+
+        *lock = Some(task_logger);
+    }
+
+    pub fn end_logging_task(&self) {
+        let mut lock = self.task_logger.write().unwrap();
+        assert!(lock.is_some(), "task should be logged before being ended");
+
+        *lock = None;
+    }
+}
+
+impl<T: Log> Log for TeaclaveLogger<T> {
+    fn enabled(&self, metadata: &Metadata) -> bool {
+        if let Some(tl) = &*self.task_logger.read().unwrap() {
+            tl.enabled(metadata)
+        } else if let Some(sl) = &self.secondary_logger {
+            sl.enabled(metadata)
+        } else {
+            false
+        }
+    }
+
+    fn log(&self, record: &Record) {
+        let kv = record.key_values();
+
+        if let Some(v) = kv.get("buffer".into()) {
+            let addr = v.to_u64().unwrap();
+
+            if addr == 0 {
+                self.end_logging_task();
+            } else {
+                let task_logger = TaskLogger::new(addr);
+                self.log_task(task_logger);
+            }
+
+            // Ignore the message when task_id is set
+            return;
+        }
+
+        let mut lock = self.task_logger.write().unwrap();
+        if let Some(ref mut tl) = *lock {
+            tl.log(record);
+            return;
+        }
+
+        if let Some(sl) = &self.secondary_logger {
+            sl.log(record)
+        }
+    }
+
+    fn flush(&self) {
+        let mut lock = self.task_logger.write().unwrap();
+
+        if let Some(ref mut tl) = *lock {
+            tl.flush();
+            return;
+        }
+
+        if let Some(sl) = &self.secondary_logger {
+            sl.flush()
+        }
+    }
+}
+
+pub struct Builder<T> {
+    secondary_logger: Option<T>,
+}
+
+impl<T: Log + 'static> Builder<T> {
+    pub fn new() -> Self {
+        Default::default()
+    }
+
+    pub fn secondary_logger(mut self, logger: T) -> Self {
+        self.secondary_logger = Some(logger);
+        self
+    }
+
+    fn build(self) -> TeaclaveLogger<T> {
+        let task_logger = RwLock::new(None);
+
+        TeaclaveLogger {
+            task_logger,
+            secondary_logger: self.secondary_logger,
+        }
+    }
+
+    pub fn init(self) {
+        // Two loggers may be used, so we set the level to trace, and filter inside function log.
+        log::set_max_level(LevelFilter::Trace);
+
+        let logger = self.build();
+
+        log::set_boxed_logger(Box::new(logger)).unwrap();
+    }
+}
+
+impl<T> Default for Builder<T> {
+    fn default() -> Self {
+        Self {
+            secondary_logger: None,
+        }
+    }
+}
+
+#[cfg(feature = "enclave_unit_test")]
+pub mod tests {
+    use teaclave_test_utils::*;
+
+    pub fn run_tests() -> bool {
+        run_tests!(test_log,)
+    }
+
+    // The logs are not sent to the storage service as the service client is not configured in
+    // teaclave_unit_tests.
+    fn test_log() {
+        log::trace!(task_id = "dummy"; "you should not see this line");
+        log::info!("you should see this line from the secondary logger");
+        log::warn!(task_id = ""; "");
+    }
+}
diff --git a/logger/src/task_logger.rs b/logger/src/task_logger.rs
new file mode 100644
index 00000000..7720f9bc
--- /dev/null
+++ b/logger/src/task_logger.rs
@@ -0,0 +1,62 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use std::sync::{Arc, Mutex};
+
+use log::{Metadata, Record};
+
+pub struct TaskLogger {
+    buffer: Arc<Mutex<Vec<String>>>,
+}
+
+impl TaskLogger {
+    pub fn new(addr: u64) -> Self {
+        let buffer = unsafe { Arc::from_raw(std::ptr::from_exposed_addr_mut(addr as usize)) };
+
+        Self { buffer }
+    }
+}
+
+impl TaskLogger {
+    pub fn enabled(&self, _metadata: &Metadata) -> bool {
+        true
+    }
+
+    pub fn log(&mut self, record: &Record) {
+        let metadata = record.metadata();
+
+        if !self.enabled(metadata) {
+            return;
+        }
+
+        let mut output = format!("[{}", metadata.level());
+        if let Some(module_path) = record.module_path() {
+            output += " ";
+            output += module_path;
+        }
+        let output = format!("{}] {}", output, record.args());
+        self.buffer.lock().unwrap().push(output);
+    }
+
+    pub fn flush(&mut self) {}
+}
+
+impl Drop for TaskLogger {
+    fn drop(&mut self) {
+        self.flush()
+    }
+}
diff --git a/sdk/rust/src/bindings.rs b/sdk/rust/src/bindings.rs
index 67d2c3ff..5b388ed3 100644
--- a/sdk/rust/src/bindings.rs
+++ b/sdk/rust/src/bindings.rs
@@ -371,7 +371,7 @@ pub unsafe extern "C" fn teaclave_get_task_result(
 
     let task_id = CStr::from_ptr(task_id).to_string_lossy().into_owned();
     match client.get_task_result(&task_id) {
-        Ok(result) => {
+        Ok((result, _)) => {
             if *task_result_len < result.len() {
                 return 1;
             } else {
diff --git a/sdk/rust/src/lib.rs b/sdk/rust/src/lib.rs
index 69c9f3a9..d4243a8c 100644
--- a/sdk/rust/src/lib.rs
+++ b/sdk/rust/src/lib.rs
@@ -495,7 +495,7 @@ impl FrontendClient {
         Ok(serialized_response)
     }
 
-    pub fn get_task_result(&mut self, task_id: &str) -> Result<Vec<u8>> {
+    pub fn get_task_result(&mut self, task_id: &str) -> Result<(Vec<u8>, Vec<String>)> {
         loop {
             let request = GetTaskRequest::new(task_id.try_into()?);
             let response = self.get_task_with_request(request)?;
@@ -504,7 +504,7 @@ impl FrontendClient {
                     std::thread::sleep(std::time::Duration::from_secs(1));
                 }
                 TaskResult::Ok(task_outputs) => {
-                    return Ok(task_outputs.return_value);
+                    return Ok((task_outputs.return_value, task_outputs.log));
                 }
                 TaskResult::Err(task_error) => {
                     return Err(anyhow::anyhow!(task_error.reason));
@@ -610,8 +610,9 @@ mod tests {
             .unwrap();
 
         let _ = client.invoke_task(&task_id).unwrap();
-        let result = client.get_task_result(&task_id).unwrap();
-        assert_eq!(result, b"Hello, Teaclave!")
+        let (result, log) = client.get_task_result(&task_id).unwrap();
+        assert_eq!(result, b"Hello, Teaclave!");
+        assert!(log.is_empty());
     }
 
     #[test]
diff --git a/services/execution/enclave/Cargo.toml b/services/execution/enclave/Cargo.toml
index 99e6b8c8..a13bf0fc 100644
--- a/services/execution/enclave/Cargo.toml
+++ b/services/execution/enclave/Cargo.toml
@@ -45,7 +45,7 @@ cov = ["teaclave_service_enclave_utils/cov"]
 enclave_unit_test = ["teaclave_binder/enclave_unit_test", "teaclave_test_utils/mesalock_sgx"]
 
 [dependencies]
-log           = { version = "0.4.17", features = ["release_max_level_info"] }
+log           = { version = "0.4.17", features = ["release_max_level_info", "kv_unstable_std"] }
 anyhow        = { version = "1.0.26" }
 serde_json    = { version = "1.0.39" }
 serde         = { version = "1.0.92", features = ["derive"] }
diff --git a/services/execution/enclave/src/lib.rs b/services/execution/enclave/src/lib.rs
index ee3e7772..e9d9ce6d 100644
--- a/services/execution/enclave/src/lib.rs
+++ b/services/execution/enclave/src/lib.rs
@@ -15,6 +15,8 @@
 // specific language governing permissions and limitations
 // under the License.
 
+#![feature(strict_provenance)]
+
 extern crate sgx_types;
 
 use std::untrusted::path::PathEx;
diff --git a/services/execution/enclave/src/service.rs b/services/execution/enclave/src/service.rs
index 42a210ba..916b58c7 100644
--- a/services/execution/enclave/src/service.rs
+++ b/services/execution/enclave/src/service.rs
@@ -218,6 +218,19 @@ impl TeaclaveExecutionService {
 }
 
 fn invoke_task(task: &StagedTask, fusion_base: &PathBuf) -> Result<TaskOutputs> {
+    let save_log = task
+        .function_arguments
+        .get("save_log")
+        .ok()
+        .and_then(|v| v.as_str().and_then(|s| s.parse().ok()))
+        .unwrap_or(false);
+    let log_arc = Arc::new(Mutex::new(Vec::<String>::new()));
+
+    if save_log {
+        let log_arc = Arc::into_raw(log_arc.clone());
+        log::info!(buffer = log_arc.expose_addr(); "");
+    }
+
     let file_mgr = TaskFileManager::new(
         WORKER_BASE_DIR,
         fusion_base,
@@ -232,7 +245,15 @@ fn invoke_task(task: &StagedTask, fusion_base: &PathBuf) -> Result<TaskOutputs>
     let summary = worker.invoke_function(invocation)?;
 
     let outputs_tag = finalize_task(&file_mgr)?;
-    let task_outputs = TaskOutputs::new(summary.as_bytes(), outputs_tag);
+    if save_log {
+        log::info!(buffer = 0; "");
+    }
+
+    let log = Arc::try_unwrap(log_arc)
+        .map_err(|_| anyhow::anyhow!("log buffer is referenced more than once"))?
+        .into_inner()?;
+    let task_outputs = TaskOutputs::new(summary.as_bytes(), outputs_tag, log);
+
     Ok(task_outputs)
 }
 
diff --git a/services/proto/src/proto/teaclave_common.proto b/services/proto/src/proto/teaclave_common.proto
index 4a7e88ec..405d029f 100644
--- a/services/proto/src/proto/teaclave_common.proto
+++ b/services/proto/src/proto/teaclave_common.proto
@@ -35,6 +35,7 @@ message FileCryptoInfo {
 message TaskOutputs {
   bytes return_value = 1;
   map<string, bytes> tags_map = 2;
+  repeated string log = 3;
 }
 
 message TaskFailure {
diff --git a/services/proto/src/teaclave_common.rs b/services/proto/src/teaclave_common.rs
index 8c0aa799..c36ceaf1 100644
--- a/services/proto/src/teaclave_common.rs
+++ b/services/proto/src/teaclave_common.rs
@@ -134,6 +134,7 @@ impl std::convert::TryFrom<proto::TaskOutputs> for TaskOutputs {
         let ret = TaskOutputs {
             return_value: proto.return_value,
             tags_map: proto.tags_map.try_into()?,
+            log: proto.log,
         };
         Ok(ret)
     }
@@ -143,6 +144,7 @@ impl std::convert::From<TaskOutputs> for proto::TaskOutputs {
         proto::TaskOutputs {
             return_value: outputs.return_value,
             tags_map: outputs.tags_map.into(),
+            log: outputs.log,
         }
     }
 }
diff --git a/services/utils/service_enclave_utils/Cargo.toml b/services/utils/service_enclave_utils/Cargo.toml
index 1d54e0b8..53ba9f96 100644
--- a/services/utils/service_enclave_utils/Cargo.toml
+++ b/services/utils/service_enclave_utils/Cargo.toml
@@ -26,9 +26,6 @@ edition = "2021"
 [features]
 default = []
 mesalock_sgx = [
-    "env_logger/termcolor",
-    "env_logger/humantime",
-    "env_logger/regex",
     "teaclave_types/mesalock_sgx",
     "teaclave_attestation/mesalock_sgx",
     "teaclave_rpc/mesalock_sgx",
@@ -40,11 +37,13 @@ anyhow     = { version = "1.0.26" }
 env_logger = { version = "0.9.3", default_features = false }
 log        = { version = "0.4.17", features = ["release_max_level_info"] }
 
+teaclave_attestation                      = { path = "../../../attestation" }
+teaclave_config                           = { path = "../../../config" }
+teaclave_logger                           = { path = "../../../logger" }
+teaclave_proto                            = { path = "../../proto" }
+teaclave_rpc                              = { path = "../../../rpc" }
 teaclave_service_enclave_utils_proc_macro = { path = "./proc_macro" }
-teaclave_types       = { path = "../../../types" }
-teaclave_attestation = { path = "../../../attestation" }
-teaclave_rpc         = { path = "../../../rpc" }
-teaclave_config      = { path = "../../../config" }
+teaclave_types                            = { path = "../../../types" }
 
-sgx_cov  = { version = "2.0.0", optional = true }
+sgx_cov     = { version = "2.0.0", optional = true }
 sgx_macros  = { version = "2.0.0", optional = true }
diff --git a/services/utils/service_enclave_utils/src/lib.rs b/services/utils/service_enclave_utils/src/lib.rs
index fe79224f..3be3e4bf 100644
--- a/services/utils/service_enclave_utils/src/lib.rs
+++ b/services/utils/service_enclave_utils/src/lib.rs
@@ -15,9 +15,12 @@
 // specific language governing permissions and limitations
 // under the License.
 
+#![feature(concat_idents)]
+
 #[cfg(feature = "mesalock_sgx")]
 extern crate sgx_trts;
 
+use anyhow::Result;
 use log::debug;
 use log::error;
 use std::backtrace;
@@ -30,7 +33,7 @@ use teaclave_attestation::AttestedTlsConfig;
 use teaclave_config::RuntimeConfig;
 use teaclave_rpc::config::SgxTrustedTlsClientConfig;
 use teaclave_rpc::endpoint::Endpoint;
-use teaclave_types::EnclaveInfo;
+use teaclave_types::{EnclaveInfo, TeeServiceError, TeeServiceResult};
 
 mod macros;
 
@@ -49,24 +52,26 @@ extern "C" {
 pub struct ServiceEnclave;
 
 impl ServiceEnclave {
-    pub fn init(_name: &str) -> teaclave_types::TeeServiceResult<()> {
-        env_logger::init_from_env(
-            env_logger::Env::new()
-                .filter_or("TEACLAVE_LOG", "RUST_LOG")
-                .write_style_or("TEACLAVE_LOG_STYLE", "RUST_LOG_STYLE"),
-        );
+    pub fn init(_name: &str) -> TeeServiceResult<()> {
+        let env = env_logger::Env::new()
+            .filter_or("TEACLAVE_LOG", "RUST_LOG")
+            .write_style_or("TEACLAVE_LOG_STYLE", "RUST_LOG_STYLE");
+        let env_logger = env_logger::Builder::from_env(env).build();
+        teaclave_logger::Builder::new()
+            .secondary_logger(env_logger)
+            .init();
 
         debug!("Enclave initializing");
 
         if backtrace::enable_backtrace(backtrace::PrintFormat::Full).is_err() {
             error!("Cannot enable backtrace");
-            return Err(teaclave_types::TeeServiceError::SgxError);
+            return Err(TeeServiceError::SgxError);
         }
 
         Ok(())
     }
 
-    pub fn finalize() -> teaclave_types::TeeServiceResult<()> {
+    pub fn finalize() -> TeeServiceResult<()> {
         debug!("Enclave finalizing");
         unsafe {
             debug!("g_peak_heap_used: {}", g_peak_heap_used);
@@ -80,15 +85,15 @@ impl ServiceEnclave {
     }
 }
 
-pub fn base_dir_for_db(config: &RuntimeConfig) -> anyhow::Result<PathBuf> {
+pub fn base_dir_for_db(config: &RuntimeConfig) -> Result<PathBuf> {
     base_dir(config, "database")
 }
 
-pub fn base_dir_for_offload_functions(config: &RuntimeConfig) -> anyhow::Result<PathBuf> {
+pub fn base_dir_for_offload_functions(config: &RuntimeConfig) -> Result<PathBuf> {
     base_dir(config, "functions")
 }
 
-fn base_dir(config: &RuntimeConfig, sub_name: &str) -> anyhow::Result<PathBuf> {
+fn base_dir(config: &RuntimeConfig, sub_name: &str) -> Result<PathBuf> {
     let fusion_base = config.mount.fusion_base_dir.as_path();
     // We only create this base directory in test_mode
     // This directory should be mounted in release mode
@@ -125,7 +130,7 @@ macro_rules! impl_create_trusted_endpoint_fn {
             as_root_ca_cert: &[u8],
             verifier: AttestationReportVerificationFn,
             attested_tls_config: Arc<RwLock<AttestedTlsConfig>>,
-        ) -> anyhow::Result<Endpoint> {
+        ) -> Result<Endpoint> {
             let service_enclave_attrs = enclave_info
                 .get_enclave_attr($enclave_attr)
                 .expect("enclave_info");
diff --git a/tests/functional/enclave/src/execution_service.rs b/tests/functional/enclave/src/execution_service.rs
index e1b29f6d..f645f16f 100644
--- a/tests/functional/enclave/src/execution_service.rs
+++ b/tests/functional/enclave/src/execution_service.rs
@@ -39,7 +39,8 @@ fn test_execute_function() {
         .function_name("builtin-echo")
         .executor(Executor::Builtin)
         .function_arguments(hashmap!(
-            "message" => "Hello, Teaclave Tests!"
+            "message" => "Hello, Teaclave Tests!",
+            "save_log" => "true",
         ))
         .build();
 
@@ -57,8 +58,12 @@ fn test_execute_function() {
     let get_request = GetRequest::new(ts.key().as_slice());
     let get_response = storage_client.get(get_request).unwrap();
     let updated_task = TaskState::from_slice(get_response.value.as_slice()).unwrap();
+    let result = updated_task.result.unwrap();
+    assert_eq!(result.return_value, b"Hello, Teaclave Tests!");
+    let info_log = result.log.iter().find(|l| l.contains("INFO")).unwrap();
+
     assert_eq!(
-        updated_task.result.unwrap().return_value,
-        b"Hello, Teaclave Tests!"
+        info_log,
+        "[INFO teaclave_function::echo] Hello, Teaclave Tests!"
     );
 }
diff --git a/tests/functional/enclave/src/scheduler_service.rs b/tests/functional/enclave/src/scheduler_service.rs
index a08a3b34..e660490d 100644
--- a/tests/functional/enclave/src/scheduler_service.rs
+++ b/tests/functional/enclave/src/scheduler_service.rs
@@ -103,7 +103,7 @@ fn test_update_task_status_result() {
     let response = client.update_task_status(request);
     assert!(response.is_ok());
 
-    let task_outputs = TaskOutputs::new("return value", hashmap!());
+    let task_outputs = TaskOutputs::new("return value", hashmap!(), vec![]);
     let request = UpdateTaskResultRequest::new(task_id, Ok(task_outputs));
     let response = client.update_task_result(request);
 
diff --git a/tests/unit/enclave/Cargo.toml b/tests/unit/enclave/Cargo.toml
index 40596af5..3eda321f 100644
--- a/tests/unit/enclave/Cargo.toml
+++ b/tests/unit/enclave/Cargo.toml
@@ -39,6 +39,8 @@ mesalock_sgx = [
   "teaclave_types/enclave_unit_test",
   "teaclave_crypto/mesalock_sgx",
   "teaclave_crypto/enclave_unit_test",
+  "teaclave_logger/mesalock_sgx",
+  "teaclave_logger/enclave_unit_test",
   "teaclave_config/mesalock_sgx",
   "teaclave_access_control_service_enclave/mesalock_sgx",
   "teaclave_access_control_service_enclave/enclave_unit_test",
@@ -98,6 +100,7 @@ teaclave_rpc                   = { path = "../../../rpc" }
 teaclave_service_enclave_utils = { path = "../../../services/utils/service_enclave_utils" }
 teaclave_types                 = { path = "../../../types" }
 teaclave_crypto                = { path = "../../../crypto" }
+teaclave_logger                = { path = "../../../logger" }
 
 [target.'cfg(not(target_vendor = "teaclave"))'.dependencies]
 sgx_types = { version = "2.0.0" }
diff --git a/tests/unit/enclave/src/lib.rs b/tests/unit/enclave/src/lib.rs
index c904e0c4..b3bd4da7 100644
--- a/tests/unit/enclave/src/lib.rs
+++ b/tests/unit/enclave/src/lib.rs
@@ -43,6 +43,7 @@ fn handle_run_test(_: &RunTestInput) -> TeeServiceResult<RunTestOutput> {
         teaclave_types::tests::run_tests(),
         teaclave_crypto::tests::run_tests(),
         rusty_leveldb::tests::run_tests(),
+        teaclave_logger::tests::run_tests(),
     );
 
     assert!(ret);
diff --git a/types/src/task.rs b/types/src/task.rs
index fea76ffe..17928877 100644
--- a/types/src/task.rs
+++ b/types/src/task.rs
@@ -213,13 +213,19 @@ impl std::iter::FromIterator<(String, FileAuthTag)> for OutputsTags {
 pub struct TaskOutputs {
     pub return_value: Vec<u8>,
     pub tags_map: OutputsTags,
+    pub log: Vec<String>,
 }
 
 impl TaskOutputs {
-    pub fn new(value: impl Into<Vec<u8>>, tags_map: HashMap<String, FileAuthTag>) -> Self {
+    pub fn new(
+        value: impl Into<Vec<u8>>,
+        tags_map: HashMap<String, FileAuthTag>,
+        log: Vec<String>,
+    ) -> Self {
         TaskOutputs {
             return_value: value.into(),
             tags_map: OutputsTags::new(tags_map),
+            log,
         }
     }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@teaclave.apache.org
For additional commands, e-mail: commits-help@teaclave.apache.org