Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ readme = "README.md"
[features]
# Uses gp_log_add_func instead of gp_context_set_log_func for logging (not supported on many systems)
extended_logs = []
test = ["libgphoto2_sys/test"]
test = ["libgphoto2_sys/test", "dep:tracing-subscriber"]
serde = ["dep:serde"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand All @@ -25,10 +25,10 @@ members = ["libgphoto2-sys", "gphoto2-test"]
[dependencies]
libgphoto2_sys = { path = "libgphoto2-sys", version = "1.2" }
libc = "0.2"
log = "0.4"
crossbeam-channel = "0.5.6"
serde = { version = "1", optional = true, features = ["derive"] }
tracing = "0.1.37"
tracing-subscriber = { version = "0.3.17", optional = true, features = ["env-filter"] }

[dev-dependencies]
env_logger = "0.9.1"
insta = "1.20.0"
4 changes: 3 additions & 1 deletion examples/bulb_capture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
//! There are also actions for capturing movies, changing liveview, etc.
//! This example will only work for Nikon DSLR cameras.

mod logging;

use gphoto2::widget::{RadioWidget, ToggleWidget};
use gphoto2::{camera::CameraEvent, Context, Result};
use std::{thread::sleep, time::Duration};

fn main() -> Result<()> {
env_logger::init();
logging::setup();

let camera = Context::new()?.autodetect_camera().wait()?;

Expand Down
4 changes: 3 additions & 1 deletion examples/camera_info.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
mod logging;

use gphoto2::{Context, Result};

fn main() -> Result<()> {
env_logger::init();
logging::setup();

let camera = Context::new()?.autodetect_camera().wait()?;

Expand Down
4 changes: 3 additions & 1 deletion examples/camera_ls.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
mod logging;

use gphoto2::{filesys::CameraFS, Context, Result};
use std::collections::HashMap;

Expand All @@ -24,7 +26,7 @@ fn list_folder_recursive(fs: &CameraFS, folder_name: &str) -> Result<FolderConte
}

fn main() -> Result<()> {
env_logger::init();
logging::setup();

let camera = Context::new()?.autodetect_camera().wait()?;
let fs = camera.fs();
Expand Down
4 changes: 3 additions & 1 deletion examples/camera_progress.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#![allow(dead_code)] // This is just an example

mod logging;

use gphoto2::{Context, Result};
use std::{collections::HashMap, path::Path};

Expand Down Expand Up @@ -60,7 +62,7 @@ impl ContextProgress {
fn main() -> Result<()> {
let mut context = Context::new()?;

env_logger::init();
logging::setup();

context.set_progress_handlers(ProgressManager::new());

Expand Down
4 changes: 3 additions & 1 deletion examples/capture.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
mod logging;

use gphoto2::{Context, Result};
use std::path::Path;

fn main() -> Result<()> {
env_logger::init();
logging::setup();

let camera = Context::new()?.autodetect_camera().wait()?;

Expand Down
4 changes: 3 additions & 1 deletion examples/capture_preview.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
//! Capture a preview and save it to /tmp/preview_image

mod logging;

use gphoto2::{Context, Result};
use std::{fs, io::Write};

fn main() -> Result<()> {
env_logger::init();
logging::setup();

let context = Context::new()?;
let camera = context.autodetect_camera().wait()?;
Expand Down
4 changes: 3 additions & 1 deletion examples/drop_camera.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
//! Test if the camera can be dropped while there are is still eg. a widget of that camera present

mod logging;

use gphoto2::{Context, Result};

fn main() -> Result<()> {
env_logger::init();
logging::setup();

let camera = Context::new()?.autodetect_camera().wait()?;

Expand Down
4 changes: 3 additions & 1 deletion examples/list_cameras.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
mod logging;

use gphoto2::list::CameraDescriptor;
use gphoto2::{Context, Result};

fn main() -> Result<()> {
env_logger::init();
logging::setup();

let context = Context::new()?;

Expand Down
4 changes: 3 additions & 1 deletion examples/list_config.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
//! Recursively list all configuration
//! Warning: Output might be very large

mod logging;

use gphoto2::{Context, Result};

fn main() -> Result<()> {
env_logger::init();
logging::setup();

let camera = Context::new()?.autodetect_camera().wait()?;
println!("{:#?}", camera.config().wait()?);
Expand Down
13 changes: 13 additions & 0 deletions examples/logging.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use tracing_subscriber::{prelude::*, EnvFilter};

pub fn setup() {
tracing_subscriber::registry()
.with(EnvFilter::from_default_env())
Copy link
Collaborator

@RReverser RReverser Jul 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe just tracing_subscriber::fmt::init() is enough to do all of this. So you don't even need a separate module.

https://docs.rs/tracing-subscriber/latest/tracing_subscriber/fmt/index.html#filtering-events-with-environment-variables:

The default subscriber installed by init enables you to filter events at runtime using environment variables (using the EnvFilter).

At least that's how I always use it.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the same apply to src/lib.rs:45 ?

.with(tracing_subscriber::fmt::layer())
.init();
}

#[allow(dead_code)]
fn main() {
eprintln!("This is only a library file")
}
4 changes: 3 additions & 1 deletion examples/opcode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
//! This example starts and ends live view mode on the camera for 10 s,
//! this example only works on Nikon cameras.

mod logging;

use gphoto2::widget::TextWidget;
use gphoto2::{Context, Result};
use std::{thread, time::Duration};

fn main() -> Result<()> {
env_logger::init();
logging::setup();

let camera = Context::new()?.autodetect_camera().wait()?;

Expand Down
4 changes: 3 additions & 1 deletion examples/select_camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
//! Usage: select_camera <camera_name>
//! To get a list of connected cameras, run example list_cameras

mod logging;

use gphoto2::{Context, Result};

fn main() -> Result<()> {
env_logger::init();
logging::setup();

let camera_name = std::env::args().nth(1).expect("Missing argument: camera_model");

Expand Down
57 changes: 34 additions & 23 deletions src/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,45 +41,56 @@ impl IntoUnixFd for File {
}
}

// Code borrowed from: https://github.com/tokio-rs/tracing/issues/372#issuecomment-762529515 (remove when tokio-rs/tracing!372 is fixed)
macro_rules! event {
(target: $target:expr, $level:expr, $($args:tt)*) => {{
use ::tracing::Level;

match $level {
Level::ERROR => ::tracing::event!(target: $target, Level::ERROR, $($args)*),
Level::WARN => ::tracing::event!(target: $target, Level::WARN, $($args)*),
Level::INFO => ::tracing::event!(target: $target, Level::INFO, $($args)*),
Level::DEBUG => ::tracing::event!(target: $target, Level::DEBUG, $($args)*),
Level::TRACE => ::tracing::event!(target: $target, Level::TRACE, $($args)*),
}
}};
}

#[cfg(feature = "extended_logs")]
pub fn hook_gp_log() {
use libgphoto2_sys::GPLogLevel;
use log::LevelFilter;
use tracing::Level;

unsafe extern "C" fn log_function(
level: libgphoto2_sys::GPLogLevel,
domain: *const std::os::raw::c_char,
_domain: *const std::os::raw::c_char,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait dynamic domain also can't be passed to tracing? 😢

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you could at least pass it as extra variable using tracing's structured logging like

tracing::event!(target: "gphoto2", Level::TRACE, scope, message)

message: *const std::os::raw::c_char,
_data: *mut ffi::c_void,
) {
let log_level = match level {
GPLogLevel::GP_LOG_ERROR => log::Level::Error,
GPLogLevel::GP_LOG_DEBUG => log::Level::Debug,
GPLogLevel::GP_LOG_VERBOSE => log::Level::Info,
GPLogLevel::GP_LOG_DATA => log::Level::Trace,
GPLogLevel::GP_LOG_ERROR => Level::ERROR,
GPLogLevel::GP_LOG_DEBUG => Level::DEBUG,
GPLogLevel::GP_LOG_VERBOSE => Level::INFO,
GPLogLevel::GP_LOG_DATA => Level::TRACE,
};

let target = format!("gphoto2::{}", chars_to_string(domain));
// let target = format!("gphoto2::{}", chars_to_string(domain)); -> Can't use this until tokio-rs/tracing!372 is resolved

log::log!(target: &target, log_level, "{}", chars_to_string(message));
event!(target: "gphoto2", log_level, "{}", chars_to_string(message));
}

let max_log_level = match log::STATIC_MAX_LEVEL {
LevelFilter::Debug | LevelFilter::Warn => GPLogLevel::GP_LOG_DEBUG,
LevelFilter::Error => GPLogLevel::GP_LOG_ERROR,
LevelFilter::Info => GPLogLevel::GP_LOG_VERBOSE,
LevelFilter::Trace => GPLogLevel::GP_LOG_DATA,
LevelFilter::Off => return,
};

HOOK_LOG_FUNCTION.call_once(|| unsafe {
libgphoto2_sys::gp_log_add_func(max_log_level, Some(log_function), std::ptr::null_mut());
libgphoto2_sys::gp_log_add_func(
GPLogLevel::GP_LOG_DEBUG,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably use https://docs.rs/tracing/latest/tracing/level_filters/constant.STATIC_MAX_LEVEL.html to match previous behaviour / optimisation that used log::STATIC_MAX_LEVEL.

Some(log_function),
std::ptr::null_mut(),
);
});
}

#[cfg(not(feature = "extended_logs"))]
pub fn hook_gp_context_log_func(context: *mut libgphoto2_sys::GPContext) {
use log::Level;
use tracing::Level;

unsafe extern "C" fn log_func(
_context: *mut libgphoto2_sys::GPContext,
Expand All @@ -88,24 +99,24 @@ pub fn hook_gp_context_log_func(context: *mut libgphoto2_sys::GPContext) {
) {
let log_level: Level = std::mem::transmute(log_level);

log::log!(target: "gphoto2", log_level, "{}", chars_to_string(message));
event!(target: "gphoto2", log_level, "{}", chars_to_string(message));
}

HOOK_LOG_FUNCTION.call_once(|| unsafe {
if log::log_enabled!(log::Level::Error) {
let log_level_as_ptr = std::mem::transmute(log::Level::Error);
if tracing::enabled!(Level::ERROR) {
let log_level_as_ptr = std::mem::transmute(Level::ERROR);

libgphoto2_sys::gp_context_set_error_func(context, Some(log_func), log_level_as_ptr);

// `gp_context_message` seems to be used also for error messages.
libgphoto2_sys::gp_context_set_message_func(context, Some(log_func), log_level_as_ptr);
}

if log::log_enabled!(log::Level::Info) {
if tracing::enabled!(Level::INFO) {
libgphoto2_sys::gp_context_set_status_func(
context,
Some(log_func),
std::mem::transmute(log::Level::Info),
std::mem::transmute(Level::INFO),
);
}
});
Expand Down
10 changes: 4 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,13 @@ compile_error!("The test feature must be enabled to run the tests");
#[cfg(all(test, feature = "test"))]
fn sample_context() -> Context {
use std::sync::Once;
use tracing_subscriber::{fmt, prelude::*, EnvFilter};

static INIT: Once = Once::new();
INIT.call_once(|| {
// Enable logging.
env_logger::builder()
// As much logging as possible.
.filter_module("gphoto2", log::LevelFilter::max())
// But hide logs if tests are successful.
.is_test(true)
tracing_subscriber::registry()
.with(fmt::layer())
.with(EnvFilter::from_default_env().add_directive("gphoto2=trace".parse().unwrap()))
.init();

// Tell libgphoto2 to look for drivers in a custom built directory.
Expand Down