+use dlog::{BufferId, Priority};
+use dlog_sys::{log_id_t, log_priority};
+use dlogutil_sys::*;
+use libc::timespec;
+use std::ffi::CStr;
+use std::io::{Error, ErrorKind, Result};
+use std::ptr::{null, null_mut};
+use std::time::Duration;
+
+/// Enumeration for timestamp-based log sorting orderings.
+///
+/// For more detailed information on the timestamp documentation,
+/// refer to the C library documentation.
+#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
+pub enum SortingOrder {
+ /// Monotonic timestamp applied by the sender.
+ SentMono,
+ /// Real-time timestamp applied by the sender.
+ SentReal,
+ /// Monotonic timestamp applied by the receiver.
+ RecvMono,
+ /// Real-time timestamp applied by the receiver.
+ RecvReal,
+ /// The default timestamp of the buffer. See [`buffer_get_default_ts_type`].
+ Default,
+}
+
+impl From<dlogutil_sorting_order> for SortingOrder {
+ fn from(c_enum: dlogutil_sorting_order) -> Self {
+ match c_enum {
+ dlogutil_sorting_order::DLOGUTIL_SORT_SENT_MONO => SortingOrder::SentMono,
+ dlogutil_sorting_order::DLOGUTIL_SORT_SENT_REAL => SortingOrder::SentReal,
+ dlogutil_sorting_order::DLOGUTIL_SORT_RECV_MONO => SortingOrder::RecvMono,
+ dlogutil_sorting_order::DLOGUTIL_SORT_RECV_REAL => SortingOrder::RecvReal,
+ dlogutil_sorting_order::DLOGUTIL_SORT_DEFAULT => SortingOrder::Default,
+ }
+ }
+}
+
+impl From<SortingOrder> for dlogutil_sorting_order {
+ fn from(rust_enum: SortingOrder) -> Self {
+ match rust_enum {
+ SortingOrder::SentMono => dlogutil_sorting_order::DLOGUTIL_SORT_SENT_MONO,
+ SortingOrder::SentReal => dlogutil_sorting_order::DLOGUTIL_SORT_SENT_REAL,
+ SortingOrder::RecvMono => dlogutil_sorting_order::DLOGUTIL_SORT_RECV_MONO,
+ SortingOrder::RecvReal => dlogutil_sorting_order::DLOGUTIL_SORT_RECV_REAL,
+ SortingOrder::Default => dlogutil_sorting_order::DLOGUTIL_SORT_DEFAULT,
+ }
+ }
+}
+
+/// A struct containing libdlogutil initialisation configuration.
+pub struct DlogutilConfig {
+ config: *mut dlogutil_config,
+}
+
+// SAFETY: it is ok to use the this object from different threads if only one thread
+// is using the memory at the time.
+unsafe impl Send for DlogutilConfig {}
+
+// SAFETY: the operations that do not modify the memory at all are ok to be used from
+// different threads at once, and those who do are marked as &mut.
+unsafe impl Sync for DlogutilConfig {}
+
+/// A struct containing the state of a log handling request.
+pub struct DlogutilState {
+ state: *mut dlogutil_state,
+}
+
+// SAFETY: it is ok to use the this object from different threads if only one thread
+// is using the memory at the time.
+unsafe impl Send for DlogutilState {}
+
+// SAFETY: the operations that do not modify the memory at all are ok to be used from
+// different threads at once, and those who do are marked as &mut.
+unsafe impl Sync for DlogutilState {}
+
+/// A struct containing the metadata and contents for a single dlog entry.
+pub struct DlogutilEntry {
+ entry: *mut dlogutil_entry,
+}
+
+// SAFETY: it is ok to use the this object from different threads if only one thread
+// is using the memory at the time.
+unsafe impl Send for DlogutilEntry {}
+
+// SAFETY: the operations that do not modify the memory at all are ok to be used from
+// different threads at once, and those who do are marked as &mut.
+unsafe impl Sync for DlogutilEntry {}
+
+impl Drop for DlogutilConfig {
+ fn drop(&mut self) {
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // Since the function takes &mut, no other references can exist.
+ unsafe {
+ dlogutil_config_destroy(self.config);
+ }
+ }
+}
+
+impl Drop for DlogutilState {
+ fn drop(&mut self) {
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // Since the function takes &mut, no other references can exist.
+ unsafe {
+ dlogutil_state_destroy(self.state);
+ }
+ }
+}
+
+impl Drop for DlogutilEntry {
+ fn drop(&mut self) {
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // Since the function takes &mut, no other references can exist.
+ unsafe {
+ dlogutil_entry_destroy(self.entry);
+ }
+ }
+}
+
+impl DlogutilConfig {
+ /// Creates a new [`DlogutilConfig`] struct to be filled with configuration.
+ ///
+ /// Useful for dumping the logs of a specific thread in a multithreaded process.
+ ///
+ /// # Returns
+ ///
+ /// * `Ok(Self)` - A handle to the config struct.
+ /// * `Err(std::io::Error)` - An error.
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::OutOfMemory`] - Out of memory.
+ pub fn create() -> Result<Self> {
+ // SAFETY: the function is safe by itself. It returns either a valid pointer,
+ // in which case we return Ok, or NULL, in which case we return Err, which
+ // means that if Self is created, the inner pointer is guaranteed to be correct.
+ let config = unsafe { dlogutil_config_create() };
+ if config.is_null() {
+ return Err(Error::from(ErrorKind::OutOfMemory));
+ }
+ Ok(DlogutilConfig { config })
+ }
+
+ /// Enables retrieving only those logs that are logged by the thread with
+ /// the given TID.
+ ///
+ /// Useful for dumping the logs of a specific thread in a multithreaded process.
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::InvalidInput`] - The pointer was NULL.
+ /// * [`std::io::ErrorKind::OutOfMemory`] - Out of memory.
+ pub fn filter_tid(&mut self, tid: i32) -> Result<()> {
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // Since the function takes &mut, no other references can exist.
+ match unsafe { dlogutil_config_filter_tid(self.config, tid) } {
+ 0 => Ok(()),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+
+ /// Enables retrieving only those logs that are logged by the process with
+ /// the given PID.
+ ///
+ /// Useful for dumping the logs of a specific process.
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::InvalidInput`] - The pointer was NULL.
+ /// * [`std::io::ErrorKind::OutOfMemory`] - Out of memory.
+ pub fn filter_pid(&mut self, pid: i32) -> Result<()> {
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // Since the function takes &mut, no other references can exist.
+ match unsafe { dlogutil_config_filter_pid(self.config, pid) } {
+ 0 => Ok(()),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+
+ /// Enables retrieving only those logs that match a given filter.
+ ///
+ /// # Arguments
+ ///
+ /// * `query` - The filter query. For syntax, see dlogutil's --help.
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::InvalidInput`] - Invalid syntax of the filterspec.
+ /// * [`std::io::ErrorKind::InvalidInput`] - The pointer was NULL.
+ /// * [`std::io::ErrorKind::OutOfMemory`] - Out of memory.
+ pub fn filter_filterspec(&mut self, query: &str) -> Result<()> {
+ let query = format!("{}\0", query);
+ let query_c =
+ CStr::from_bytes_with_nul(query.as_bytes()).map_err(|_| ErrorKind::InvalidInput)?;
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // The string is defined in a verified way above.
+ // Since the function takes &mut, no other references can exist.
+ match unsafe { dlogutil_config_filter_filterspec(self.config, query_c.as_ptr()) } {
+ 0 => Ok(()),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+
+ /// Disables log sorting for given log retrieval request.
+ ///
+ /// Logs are still received in some order that is usually largely sorted,
+ /// but if sorting is disabled logutil-side there may be cases where a log
+ /// with a later timestamp is in front of a log with an earlier one.
+ /// The use case here is performance, since the failure case above is rare.
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::InvalidInput`] - The pointer was NULL.
+ pub fn sorting_disable(&mut self) -> Result<()> {
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // Since the function takes &mut, no other references can exist.
+ match unsafe { dlogutil_config_sorting_disable(self.config) } {
+ 0 => Ok(()),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+
+ /// Enables log sorting for given log retrieval request.
+ ///
+ /// This is the default and generally makes sure that logs are in order,
+ /// but has a modest performance cost.
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::InvalidInput`] - The pointer was NULL.
+ pub fn sorting_enable(&mut self) -> Result<()> {
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // Since the function takes &mut, no other references can exist.
+ match unsafe { dlogutil_config_sorting_enable(self.config) } {
+ 0 => Ok(()),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+
+ /// Enables sorting, choosing the sort buffer size manually.
+ ///
+ /// The count parameter influences the quality of sorting, but also memory usage.
+ /// This version is a somewhat lower level version of [`sorting_enable`].
+ /// For more information on sorting quality, refer to the C library documentation.
+ ///
+ /// [`sorting_enable`]: DlogutilConfig::sorting_enable
+ ///
+ /// # Arguments
+ ///
+ /// * `entry_count` - How many logs to keep at a given time. At least 1.
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::InvalidInput`] - Zero size.
+ /// * [`std::io::ErrorKind::InvalidInput`] - The pointer was NULL.
+ pub fn sorting_enable_with_size(&mut self, entry_count: u32) -> Result<()> {
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // Since the function takes &mut, no other references can exist.
+ match unsafe { dlogutil_config_sorting_enable_with_size(self.config, entry_count) } {
+ 0 => Ok(()),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+
+ /// Chooses a timestamp type by which returned logs are sorted by.
+ ///
+ /// If the chosen timestamp is missing in the logs, currently they will not
+ /// be sorted at all. This should, however, still become a reasonable order,
+ /// since logs are usually stored sorted by one of timestamps. If only some
+ /// logs are missing the chosen timestamp, ordering of the logs is undefined.
+ /// See [`buffer_get_default_ts_type`] for the default.
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::InvalidInput`] - The pointer was NULL.
+ pub fn order_set(&mut self, sort_by: SortingOrder) -> Result<()> {
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // Since the function takes &mut, no other references can exist.
+ match unsafe { dlogutil_config_order_set(self.config, sort_by.into()) } {
+ 0 => Ok(()),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+
+ /// Adds a buffer whence logs will be taken to a request.
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::InvalidInput`] - The pointer was NULL.
+ pub fn buffer_add(&mut self, buf: BufferId) -> Result<()> {
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // Since the function takes &mut, no other references can exist.
+ match unsafe { dlogutil_config_buffer_add(self.config, buf.into()) } {
+ 0 => Ok(()),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+
+ /// Set log retrieval mode to retrieving all the logs since the start of
+ /// the system without an end.
+ ///
+ /// This is similar to `dlogutil` in a default mode.
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::InvalidInput`] - The pointer was NULL.
+ pub fn mode_set_continuous(&mut self) -> Result<()> {
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // Since the function takes &mut, no other references can exist.
+ match unsafe { dlogutil_config_mode_set_continuous(self.config) } {
+ 0 => Ok(()),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+
+ /// Set log retrieval mode to retrieving all the logs since the call
+ /// without an end.
+ ///
+ /// This is similar to `dlogutil -m`.
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::InvalidInput`] - The pointer was NULL.
+ pub fn mode_set_monitor(&mut self) -> Result<()> {
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // Since the function takes &mut, no other references can exist.
+ match unsafe { dlogutil_config_mode_set_monitor(self.config) } {
+ 0 => Ok(()),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+
+ /// Set log retrieval mode to dumping all the logs since the start of the
+ /// system until the call (possibly a specified amount of the most recent
+ /// of them instead).
+ ///
+ /// This is similar to `dlogutil -d`. After dumping all the logs,
+ /// [`get_log`] will signal this by returning `TIZEN_ERROR_NO_DATA`.
+ ///
+ /// [`get_log`]: DlogutilState::get_log
+ ///
+ /// # Arguments
+ ///
+ /// * `entry_count` - Number of logs to be returned. It can be
+ /// `DLOGUTIL_MAX_DUMP_SIZE`, in which case all the logs will be dumped.
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::InvalidInput`] - The pointer was NULL.
+ pub fn mode_set_dump(&mut self, entry_count: u32) -> Result<()> {
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // Since the function takes &mut, no other references can exist.
+ match unsafe { dlogutil_config_mode_set_dump(self.config, entry_count) } {
+ 0 => Ok(()),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+
+ /// Set log retrieval mode to dumping compressed historical logs.
+ ///
+ /// This is similar to `cat /var/log/dlog/xyz`. After dumping all the logs,
+ /// [`get_log`] will signal this by returning `TIZEN_ERROR_NO_DATA`.
+ ///
+ /// [`get_log`]: DlogutilState::get_log
+ ///
+ /// # Arguments
+ ///
+ /// * `compress_buffer` - The name of the compression storage entry.
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::OutOfMemory`] - Not enough memory. Parameters left unchanged.
+ /// * [`std::io::ErrorKind::InvalidInput`] - The pointer was NULL.
+ pub fn mode_set_compressed_memory_dump(&mut self, compress_buffer: &str) -> Result<()> {
+ let compress_buffer = format!("{}\0", compress_buffer);
+ let compress_buffer_c = CStr::from_bytes_with_nul(compress_buffer.as_bytes())
+ .map_err(|_| ErrorKind::InvalidInput)?;
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // The string is defined in a verified way above.
+ // Since the function takes &mut, no other references can exist.
+ match unsafe {
+ dlogutil_config_mode_set_compressed_memory_dump(self.config, compress_buffer_c.as_ptr())
+ } {
+ 0 => Ok(()),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+}
+
+impl DlogutilState {
+ /// Finalizes the config into a state struct by connecting to buffers.
+ ///
+ /// An application having platform privilege level can read platform log
+ /// data by declaring <http://tizen.org/privilege/log>.
+ ///
+ /// # Returns
+ ///
+ /// * `Ok(Self)` - A handle to the state struct.
+ /// * `Err(std::io::Error)` - An error.
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
+ /// * [`std::io::ErrorKind::InvalidInput`] - No buffers selected.
+ /// * [`std::io::ErrorKind::Uncategorized`] - Unsupported buffer set (KMSG + non-KMSG).
+ /// * [`std::io::ErrorKind::Uncategorized`] - Unsupported backend (zero-copy).
+ /// * [`std::io::ErrorKind::Uncategorized`] - No buffers were opened (incl. due to null backend).
+ /// * [`std::io::ErrorKind::Uncategorized`] - Couldn't read config file.
+ /// * [`std::io::ErrorKind::Uncategorized`] - Couldn't contact log backend.
+ /// * [`std::io::ErrorKind::OutOfMemory`] - There's not enough memory.
+ pub fn create(config: DlogutilConfig) -> Result<Self> {
+ let mut state = DlogutilState { state: null_mut() };
+ // SAFETY: the config pointer is guaranteed to be correct by the way it's created.
+ // Otherwise, the function is safe by itself. It returns either a valid pointer,
+ // in which case we return Ok, or NULL, in which case we return Err, which
+ // means that if Self is created, the inner pointer is guaranteed to be correct.
+ match unsafe { dlogutil_config_connect(config.config, &mut state.state) } {
+ 0 => Ok(state),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+
+ /// Retrieves a single log according to a dump request.
+ ///
+ /// Returns a returned log as a [`DlogutilEntry`] struct.
+ ///
+ /// If the calling process doesn't have `CAP_SYSLOG` and is not in the
+ /// log group, you will only get some of the logs.
+ /// Also, you must set the mode (`DlogutilConfig::mode_set_*`).
+ ///
+ /// [`DlogutilEntry`]: DlogutilEntry
+ ///
+ /// # Arguments
+ ///
+ /// * `timeout` - How many miliseconds to wait for the log.
+ /// The actual runtime of the call can obviously be slightly longer than
+ /// this argument. 0 means don't wait, None means wait indefinitely.
+ ///
+ /// # Returns
+ ///
+ /// * `Ok(DlogutilEntry)` - A returned log.
+ /// * `Err(std::io::Error)` - An error.
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::Uncategorized`] - Timeout exceeded.
+ /// * [`std::io::ErrorKind::Uncategorized`] - In dump mode, no more logs remaining.
+ /// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
+ /// * [`std::io::ErrorKind::InvalidInput`] - State not in log-getting mode.
+ /// * [`std::io::ErrorKind::OutOfMemory`] - There's not enough memory.
+ /// * [`std::io::ErrorKind::Uncategorized`] - Couldn't fulfill request.
+ pub fn get_log(&mut self, timeout: Option<Duration>) -> Result<DlogutilEntry> {
+ let mut entry_out = DlogutilEntry { entry: null_mut() };
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // The C function passes the ownership of the entry to the pointer iff the
+ // return value is nonzero, which is exactly the case in which we return
+ // the struct in an Ok. Since the function takes &mut, no other references can exist.
+ match unsafe {
+ dlogutil_get_log(
+ self.state,
+ timeout.map_or(-1, |t| t.as_millis() as i32),
+ &mut entry_out.entry,
+ )
+ } {
+ 0 => Ok(entry_out),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+
+ /// Irreversibly clears a log buffer from any logs inside.
+ ///
+ /// Either `CAP_SYSLOG` or being in the log group is required.
+ /// Also, you can't use one of the log-getting modes
+ /// (`DlogutilConfig::mode_set_*`).
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
+ /// * [`std::io::ErrorKind::Uncategorized`] - Couldn't fulfill request.
+ pub fn buffer_clear(&mut self, buffer: BufferId) -> Result<()> {
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // Since the function takes &mut, no other references can exist.
+ match unsafe { dlogutil_buffer_clear(self.state, buffer.into()) } {
+ 0 => Ok(()),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+
+ /// Gets the data storage capacity of a log buffer in bytes.
+ ///
+ /// Either `CAP_SYSLOG` or being in the log group is required.
+ /// Also, you can't use one of the log-getting modes
+ /// (`DlogutilConfig::mode_set_*`).
+ ///
+ /// # Returns
+ ///
+ /// * `Ok(u32)` - The buffer's maximum capacity in bytes.
+ /// * `Err(std::io::Error)` - An error.
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::InvalidInput`] - State in log-getting mode.
+ /// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
+ /// * [`std::io::ErrorKind::Uncategorized`] - Couldn't fulfill request.
+ pub fn buffer_get_capacity(&mut self, buffer: BufferId) -> Result<u32> {
+ let mut capacity = 0;
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // Note that it is not correct for this function to take a shared reference, as in case of
+ // the pipe backend, the function will write to a pipe and expect to read an answer
+ // immediately.
+ match unsafe { dlogutil_buffer_get_capacity(self.state, buffer.into(), &mut capacity) } {
+ 0 => Ok(capacity),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+
+ /// Gets the storage data usage of a log buffer in bytes.
+ ///
+ /// Either `CAP_SYSLOG` or being in the log group is required.
+ /// Also, you can't use one of the log-getting modes
+ /// (`DlogutilConfig::mode_set_*`).
+ ///
+ /// # Returns
+ ///
+ /// * `Ok(u32)` - Buffer's current usage in bytes.
+ /// * `Err(std::io::Error)` - An error.
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::InvalidInput`] - State in log-getting mode.
+ /// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
+ /// * [`std::io::ErrorKind::Uncategorized`] - Couldn't fulfill request.
+ pub fn buffer_get_usage(&mut self, buffer: BufferId) -> Result<u32> {
+ let mut usage = 0;
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // Note that it is not correct for this function to take a shared reference, as in case of
+ // the pipe backend, the function will write to a pipe and expect to read an answer
+ // immediately.
+ match unsafe { dlogutil_buffer_get_usage(self.state, buffer.into(), &mut usage) } {
+ 0 => Ok(usage),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+
+ /// Gets the buffer aliasing (same storage) information.
+ ///
+ /// Sometimes, multiple buffers will be backed by a single log storage
+ /// (for example, by the same kernel device). In such cases, the storage
+ /// will only be opened once.
+ /// This function allows you to see whether this is the case.
+ ///
+ /// # Returns
+ ///
+ /// * `Ok(BufferId)` - Buffer aliasing information.
+ /// * `Err(std::io::Error)` - An error.
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
+ pub fn buffer_get_alias(&self, buffer: BufferId) -> Result<BufferId> {
+ let mut real_buffer = log_id_t::LOG_ID_MAIN;
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // This method only reads from the memory of the object, so it is ok for it to take
+ // a shared reference.
+ match unsafe { dlogutil_buffer_get_alias(self.state, buffer.into(), &mut real_buffer) } {
+ 0 => Ok(real_buffer.into()),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+}
+
+impl DlogutilEntry {
+ /// Retrieves the timestamp of given type from the log entry.
+ ///
+ /// The information about timestamp availability can be retrieved using the
+ /// [`buffer_check_ts_type_available`] function.
+ ///
+ /// # Returns
+ ///
+ /// * `Ok(Duration)` - Timestamp of the entry as a [`Duration`] struct.
+ /// * `Err(std::io::Error)` - An error.
+ ///
+ /// [`Duration`]: std::time::Duration
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::InvalidInput`] - Invalid value of order.
+ /// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
+ /// * [`std::io::ErrorKind::Uncategorized`] - The timestamp is missing.
+ pub fn get_timestamp(&self, stamp_type: SortingOrder) -> Result<Duration> {
+ let mut ts = timespec {
+ tv_sec: 0,
+ tv_nsec: 0,
+ };
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // This method only reads from the memory of the object, so it is ok for it to take
+ // a shared reference.
+ match unsafe { dlogutil_entry_get_timestamp(self.entry, stamp_type.into(), &mut ts) } {
+ 0 => Ok(Duration::new(ts.tv_sec as u64, ts.tv_nsec as u32)),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+
+ /// Retrieves the TID (thread identificator) of the log sender.
+ ///
+ /// If [`LogIdKmsg`] is used as the buffer, this function will always return
+ /// `TIZEN_ERROR_NO_DATA`.
+ /// This is because the KMSG buffer contains no TID information.
+ ///
+ /// [`LogIdKmsg`]: BufferId::LogIdKmsg
+ ///
+ /// # Returns
+ ///
+ /// * `Ok(i32)` - TID of the log sender.
+ /// * `Err(std::io::Error)` - An error.
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
+ /// * [`std::io::ErrorKind::Uncategorized`] - TID is missing or not applicable.
+ pub fn get_tid(&self) -> Result<i32> {
+ let mut tid = 0;
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // This method only reads from the memory of the object, so it is ok for it to take
+ // a shared reference.
+ match unsafe { dlogutil_entry_get_tid(self.entry, &mut tid) } {
+ 0 => Ok(tid),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+
+ /// Retrieves the PID (process identificator) of the log sender.
+ ///
+ /// If [`LogIdKmsg`] is used as the buffer, this function will always return
+ /// `TIZEN_ERROR_NO_DATA`.
+ /// This is because the KMSG buffer contains no PID information.
+ ///
+ /// [`LogIdKmsg`]: BufferId::LogIdKmsg
+ ///
+ /// # Returns
+ ///
+ /// * `Ok(i32)` - PID of the log sender.
+ /// * `Err(std::io::Error)` - An error.
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
+ /// * [`std::io::ErrorKind::Uncategorized`] - PID is missing or not applicable.
+ pub fn get_pid(&self) -> Result<i32> {
+ let mut pid = 0;
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // This method only reads from the memory of the object, so it is ok for it to take
+ // a shared reference.
+ match unsafe { dlogutil_entry_get_pid(self.entry, &mut pid) } {
+ 0 => Ok(pid),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+
+ /// Retrieves the priority level metadata of the log entry.
+ ///
+ /// # Returns
+ ///
+ /// * `Ok(Priority)` - Log priority.
+ /// * `Err(std::io::Error)` - An error.
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
+ /// * [`std::io::ErrorKind::Uncategorized`] - The priority is missing.
+ pub fn get_priority(&self) -> Result<Priority> {
+ let mut prio = log_priority::DLOG_UNKNOWN;
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // This method only reads from the memory of the object, so it is ok for it to take
+ // a shared reference.
+ match unsafe { dlogutil_entry_get_priority(self.entry, &mut prio) } {
+ 0 => Ok(prio.into()),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+
+ /// Retrieves the tag (arbitrary label) of the log entry.
+ ///
+ /// In some rare cases the entry may be malformed and the tag
+ /// may turn out to be unavailable.
+ ///
+ /// In such cases, an empty string may be returned instead.
+ ///
+ /// # Returns
+ ///
+ /// * `Ok(&str)` - Log tag.
+ /// * `Err(std::io::Error)` - An error.
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
+ /// * [`std::io::ErrorKind::Uncategorized`] - The tag is missing.
+ pub fn get_tag(&self) -> Result<&str> {
+ let mut tag_ptr = null();
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // The function returns either NULL, in which case we return Err,
+ // or a string with same lifetime as self.entry, in which case we can safely
+ // call CStr::from_ptr and return it in an Ok.
+ // This method only reads from the memory of the object, so it is ok for it to take
+ // a shared reference.
+ unsafe {
+ match dlogutil_entry_get_tag(self.entry, &mut tag_ptr) {
+ 0 => Ok(CStr::from_ptr(tag_ptr).to_str().unwrap()),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+ }
+
+ /// Retrieves the message (without any metadata) of the log entry.
+ ///
+ /// In some rare cases the entry may be malformed and the message
+ /// may turn out to be unavailable.
+ ///
+ /// In such cases, an empty string may be returned instead.
+ ///
+ /// # Returns
+ ///
+ /// * `Ok(&str)` - Log message.
+ /// * `Err(std::io::Error)` - An error.
+ ///
+ /// # Errors
+ ///
+ /// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
+ /// * [`std::io::ErrorKind::Uncategorized`] - The message is missing.
+ pub fn get_message(&self) -> Result<&str> {
+ let mut msg_ptr = null();
+ // SAFETY: the pointer is guaranteed to be correct by the way it's created.
+ // The function returns either NULL, in which case we return Err,
+ // or a string with same lifetime as self.entry, in which case we can safely
+ // call CStr::from_ptr and return it in an Ok.
+ // This method only reads from the memory of the object, so it is ok for it to take
+ // a shared reference.
+ unsafe {
+ match dlogutil_entry_get_message(self.entry, &mut msg_ptr) {
+ 0 => Ok(CStr::from_ptr(msg_ptr).to_str().unwrap()),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+ }
+}
+
+/// Gets the human-readable, constant name of a buffer.
+///
+/// # Returns
+///
+/// * `Ok(&str)` - The name of the passed buffer.
+/// * `Err(std::io::Error)` - An error.
+///
+/// # Errors
+///
+/// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
+pub fn buffer_get_name(buffer: BufferId) -> Result<&'static str> {
+ let mut name_ptr = null();
+ // SAFETY: the function is safe by itself provided the target is a valid pointer.
+ // The function returns either NULL, in which case we return Err,
+ // or a string with static lifetime, in which case we can safely call
+ // CStr::from_ptr and return it in an Ok.
+ unsafe {
+ match dlogutil_buffer_get_name(buffer.into(), &mut name_ptr) {
+ 0 => Ok(CStr::from_ptr(name_ptr).to_str().unwrap()),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+ }
+}
+
+/// Gets the default sorting timestamp type of a buffer.
+///
+/// This is the timestamp type that will be used for sorting by default.
+/// We assume that it is always available and the input is sorted by it.
+///
+/// # Returns
+///
+/// * `Ok(SortingOrder)` - The default timestamp type of the passed buffer.
+/// * `Err(std::io::Error)` - An error.
+///
+/// # Errors
+///
+/// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
+/// * [`std::io::ErrorKind::Uncategorized`] - Couldn't read config file.
+pub fn buffer_get_default_ts_type(buffer: BufferId) -> Result<SortingOrder> {
+ let mut typ = dlogutil_sorting_order::DLOGUTIL_SORT_SENT_MONO;
+ // SAFETY: the function is safe by itself provided the target is a valid pointer.
+ match unsafe { dlogutil_buffer_get_default_ts_type(buffer.into(), &mut typ) } {
+ 0 => Ok(typ.into()),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+}
+
+/// Checks if a buffer contains timestamps of a given type.
+///
+/// If false is returned, the timestamp may still be available in some of the logs.
+/// However, if true is returned, the timestamp will always be available.
+/// You can check the timestamp availability per log using the [`get_timestamp`]
+/// function.
+///
+/// [`get_timestamp`]: DlogutilEntry::get_timestamp
+///
+/// # Returns
+///
+/// * `Ok(bool)` - Whether the given timestamp type is guaranteed to be available.
+/// * `Err(std::io::Error)` - An error.
+///
+/// # Errors
+///
+/// * [`std::io::ErrorKind::InvalidInput`] - More than one buffer.
+/// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
+/// * [`std::io::ErrorKind::Uncategorized`] - Couldn't read config file.
+pub fn buffer_check_ts_type_available(buffer: BufferId, stamp_type: SortingOrder) -> Result<bool> {
+ let mut available = false;
+ // SAFETY: the function is safe by itself provided the target is a valid pointer.
+ match unsafe {
+ dlogutil_buffer_check_ts_type_available(buffer.into(), stamp_type.into(), &mut available)
+ } {
+ 0 => Ok(available),
+ e => Err(Error::from_raw_os_error(-e)),
+ }
+}