Use tracing.

Improved logging by using tracing and tracing-subscriber rather than
log and env_logger.
This commit is contained in:
Rasmus Kaj 2022-07-17 19:27:46 +02:00
parent 2660c91732
commit 8385ea1298
18 changed files with 81 additions and 60 deletions

View File

@ -6,8 +6,10 @@ The format is based on
## Unreleased ## Unreleased
* Check for null bytes in autocomplete patterns, make them an bad * Check for null bytes in autocomplete patterns, make them result in a
request rather than an internal server error. 400 bad request rather than a 500 internal server error.
* Improved logging by using tracing and tracing-subscriber rather than
log and env_logger.
* Two more kinds of OSM area to recognize. * Two more kinds of OSM area to recognize.
* Add this changelog. * Add this changelog.

View File

@ -14,14 +14,12 @@ brotli = "3.3.0"
chrono = "0.4.0" # Must match version used by diesel chrono = "0.4.0" # Must match version used by diesel
clap = { version = "3.2.8", features = ["derive", "terminal_size", "wrap_help", "env"] } clap = { version = "3.2.8", features = ["derive", "terminal_size", "wrap_help", "env"] }
dotenv = "0.15" dotenv = "0.15"
env_logger = "0.9.0"
flate2 = "1.0.14" flate2 = "1.0.14"
image = "0.24.0" image = "0.24.0"
medallion = "2.3.1" medallion = "2.3.1"
kamadak-exif = "0.5.0" kamadak-exif = "0.5.0"
lazy-regex = "2.2.2" lazy-regex = "2.2.2"
libc = "0.2.68" libc = "0.2.68"
log = "0.4.8"
mime = "0.3.0" mime = "0.3.0"
r2d2-memcache = "0.6" r2d2-memcache = "0.6"
rand = "0.8" rand = "0.8"
@ -30,6 +28,8 @@ serde = { version = "1.0.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
slug = "0.1" slug = "0.1"
tokio = { version = "1.0.2", features = ["macros", "rt-multi-thread"] } tokio = { version = "1.0.2", features = ["macros", "rt-multi-thread"] }
tracing = "0.1.35"
tracing-subscriber = { version = "0.3.14", features = ["env-filter"] }
[dependencies.djangohashers] [dependencies.djangohashers]
default-features = false default-features = false

View File

@ -6,8 +6,8 @@ use crate::{DbOpt, DirOpt};
use diesel::insert_into; use diesel::insert_into;
use diesel::pg::PgConnection; use diesel::pg::PgConnection;
use diesel::prelude::*; use diesel::prelude::*;
use log::{debug, info, warn};
use std::path::Path; use std::path::Path;
use tracing::{debug, info, warn};
#[derive(clap::Parser)] #[derive(clap::Parser)]
pub struct Findphotos { pub struct Findphotos {

View File

@ -4,9 +4,9 @@ use crate::photosdir::{get_scaled_jpeg, PhotosDir};
use crate::schema::photos::dsl::{date, is_public}; use crate::schema::photos::dsl::{date, is_public};
use crate::{CacheOpt, DbOpt, DirOpt}; use crate::{CacheOpt, DbOpt, DirOpt};
use diesel::prelude::*; use diesel::prelude::*;
use log::{debug, info};
use r2d2_memcache::memcache::Client; use r2d2_memcache::memcache::Client;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use tracing::{debug, info};
#[derive(clap::Parser)] #[derive(clap::Parser)]
pub struct Args { pub struct Args {

View File

@ -2,8 +2,8 @@ use crate::Error;
use diesel::pg::PgConnection; use diesel::pg::PgConnection;
use diesel::r2d2::{ConnectionManager, Pool, PooledConnection}; use diesel::r2d2::{ConnectionManager, Pool, PooledConnection};
use diesel::{Connection, ConnectionError}; use diesel::{Connection, ConnectionError};
use log::debug;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use tracing::debug;
pub type PgPool = Pool<ConnectionManager<PgConnection>>; pub type PgPool = Pool<ConnectionManager<PgConnection>>;
pub type PooledPg = PooledConnection<ConnectionManager<PgConnection>>; pub type PooledPg = PooledConnection<ConnectionManager<PgConnection>>;

View File

@ -2,10 +2,10 @@ use crate::dbopt::PgPool;
use crate::models::{Coord, Place}; use crate::models::{Coord, Place};
use crate::DbOpt; use crate::DbOpt;
use diesel::prelude::*; use diesel::prelude::*;
use log::{debug, info};
use reqwest::{self, Client, Response}; use reqwest::{self, Client, Response};
use serde_json::Value; use serde_json::Value;
use slug::slugify; use slug::slugify;
use tracing::{debug, info, instrument};
#[derive(clap::Parser)] #[derive(clap::Parser)]
pub struct Fetchplaces { pub struct Fetchplaces {
@ -63,6 +63,7 @@ pub struct OverpassOpt {
} }
impl OverpassOpt { impl OverpassOpt {
#[instrument(skip(self, db))]
pub async fn update_image_places( pub async fn update_image_places(
&self, &self,
db: &PgPool, db: &PgPool,
@ -78,7 +79,7 @@ impl OverpassOpt {
.optional() .optional()
.map_err(|e| Error::Db(image, e))? .map_err(|e| Error::Db(image, e))?
.ok_or(Error::NoPosition(image))?; .ok_or(Error::NoPosition(image))?;
debug!("Should get places for #{} at {:?}", image, coord); debug!(?coord, "Should get places");
let data = Client::new() let data = Client::new()
.post(&self.overpass_url) .post(&self.overpass_url)
.body(format!("[out:json];is_in({},{});out;", coord.x, coord.y)) .body(format!("[out:json];is_in({},{});out;", coord.x, coord.y))
@ -270,7 +271,6 @@ fn name_and_level(obj: &Value) -> Option<(&str, i16)> {
.find_map(|(name, values)| tag_level(tags, name, values)) .find_map(|(name, values)| tag_level(tags, name, values))
})?; })?;
debug!("{} is level {}", name, level);
Some((name, level)) Some((name, level))
} }

View File

@ -84,7 +84,11 @@ struct DirOpt {
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
dotenv().ok(); dotenv().ok();
env_logger::init(); tracing_subscriber::fmt()
.with_env_filter(
std::env::var("RUST_LOG").as_deref().unwrap_or("info"),
)
.init();
match run(&RPhotos::from_args()).await { match run(&RPhotos::from_args()).await {
Ok(()) => (), Ok(()) => (),
Err(err) => { Err(err) => {

View File

@ -2,11 +2,11 @@
use crate::adm::result::Error; use crate::adm::result::Error;
use chrono::{Date, Local, NaiveDate, NaiveDateTime, NaiveTime, Utc}; use chrono::{Date, Local, NaiveDate, NaiveDateTime, NaiveTime, Utc};
use exif::{Field, In, Reader, Tag, Value}; use exif::{Field, In, Reader, Tag, Value};
use log::{debug, error, warn};
use std::fs::File; use std::fs::File;
use std::io::BufReader; use std::io::BufReader;
use std::path::Path; use std::path::Path;
use std::str::from_utf8; use std::str::from_utf8;
use tracing::{debug, error, warn};
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct ExifData { pub struct ExifData {

View File

@ -1,12 +1,13 @@
use crate::models::Photo; use crate::models::Photo;
use crate::myexif::ExifData; use crate::myexif::ExifData;
use image::imageops::FilterType; use image::imageops::FilterType;
use image::{self, ImageError, ImageFormat}; use image::{self, DynamicImage, ImageError, ImageFormat};
use log::{debug, info, warn};
use std::ffi::OsStr; use std::ffi::OsStr;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::time::Instant;
use std::{fs, io}; use std::{fs, io};
use tokio::task::{spawn_blocking, JoinError}; use tokio::task::{spawn_blocking, JoinError};
use tracing::{debug, info, warn};
pub struct PhotosDir { pub struct PhotosDir {
basedir: PathBuf, basedir: PathBuf,
@ -126,45 +127,59 @@ pub async fn get_scaled_jpeg(
rotation: i16, rotation: i16,
size: u32, size: u32,
) -> Result<Vec<u8>, ImageLoadFailed> { ) -> Result<Vec<u8>, ImageLoadFailed> {
spawn_blocking(move || { spawn_blocking(move || do_get_scaled_jpeg(path, rotation, size)).await?
info!("Should open {:?}", path); }
let img = if is_jpeg(&path) { #[tracing::instrument]
use std::fs::File; fn do_get_scaled_jpeg(
use std::io::BufReader; path: PathBuf,
let file = BufReader::new(File::open(path)?); rotation: i16,
let mut decoder = image::codecs::jpeg::JpegDecoder::new(file)?; size: u32,
decoder.scale(size as u16, size as u16)?; ) -> Result<Vec<u8>, ImageLoadFailed> {
image::DynamicImage::from_decoder(decoder)? let start = Instant::now();
} else { let img = if is_jpeg(&path) {
image::open(path)? use std::fs::File;
}; use std::io::BufReader;
let file = BufReader::new(File::open(path)?);
let mut decoder = image::codecs::jpeg::JpegDecoder::new(file)?;
decoder.scale(size as u16, size as u16)?;
DynamicImage::from_decoder(decoder)?
} else {
image::open(path)?
};
let img = if 3 * size <= img.width() || 3 * size <= img.height() { debug!(size = %Size(&img), elapsed = ?start.elapsed(), "Loaded image.");
info!("T-nail from {}x{} to {}", img.width(), img.height(), size); let img = if 3 * size <= img.width() || 3 * size <= img.height() {
img.thumbnail(size, size) img.thumbnail(size, size)
} else if size < img.width() || size < img.height() { } else if size < img.width() || size < img.height() {
info!("Scaling from {}x{} to {}", img.width(), img.height(), size); img.resize(size, size, FilterType::CatmullRom)
img.resize(size, size, FilterType::CatmullRom) } else {
} else { img
};
debug!(size = %Size(&img), elapsed = ?start.elapsed(), "Scaled image.");
let img = match rotation {
_x @ 0..=44 | _x @ 315..=360 => img,
_x @ 45..=134 => img.rotate90(),
_x @ 135..=224 => img.rotate180(),
_x @ 225..=314 => img.rotate270(),
x => {
warn!("Should rotate photo {} deg, which is unsupported.", x);
img img
}; }
let img = match rotation { };
_x @ 0..=44 | _x @ 315..=360 => img, debug!(elapsed = ?start.elapsed(), "Ready to save.");
_x @ 45..=134 => img.rotate90(), let mut buf = Vec::new();
_x @ 135..=224 => img.rotate180(), use std::io::Cursor;
_x @ 225..=314 => img.rotate270(), img.write_to(&mut Cursor::new(&mut buf), ImageFormat::Jpeg)?;
x => { info!(elapsed = ?start.elapsed(), "Done.");
warn!("Should rotate photo {} deg, which is unsupported", x); Ok(buf)
img }
}
}; struct Size<'a>(&'a DynamicImage);
let mut buf = Vec::new(); impl<'a> std::fmt::Display for Size<'a> {
use std::io::Cursor; fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
img.write_to(&mut Cursor::new(&mut buf), ImageFormat::Jpeg)?; write!(f, "{}x{}", self.0.width(), self.0.height())
Ok(buf) }
})
.await?
} }
fn is_jpeg(path: &Path) -> bool { fn is_jpeg(path: &Path) -> bool {

View File

@ -1,10 +1,10 @@
use crate::adm::result::Error; use crate::adm::result::Error;
use libc::{kill, pid_t, SIGHUP}; use libc::{kill, pid_t, SIGHUP};
use log::{debug, info};
use std::fs::{read_to_string, write}; use std::fs::{read_to_string, write};
use std::io::ErrorKind; use std::io::ErrorKind;
use std::path::Path; use std::path::Path;
use std::process; use std::process;
use tracing::{debug, info};
pub fn handle_pid_file(pidfile: &Path, replace: bool) -> Result<(), Error> { pub fn handle_pid_file(pidfile: &Path, replace: bool) -> Result<(), Error> {
if replace { if replace {

View File

@ -3,9 +3,9 @@ use super::error::ViewResult;
use super::{redirect_to_img, wrap, Context, Result, ViewError}; use super::{redirect_to_img, wrap, Context, Result, ViewError};
use crate::models::{Coord, Photo, SizeTag}; use crate::models::{Coord, Photo, SizeTag};
use diesel::{self, prelude::*}; use diesel::{self, prelude::*};
use log::{info, warn};
use serde::Deserialize; use serde::Deserialize;
use slug::slugify; use slug::slugify;
use tracing::{info, warn};
use warp::filters::BoxedFilter; use warp::filters::BoxedFilter;
use warp::http::response::Builder; use warp::http::response::Builder;
use warp::reply::Response; use warp::reply::Response;

View File

@ -45,7 +45,7 @@ async fn api_recover(err: Rejection) -> Result<Response, Rejection> {
} else if err.find::<MethodNotAllowed>().is_some() { } else if err.find::<MethodNotAllowed>().is_some() {
StatusCode::METHOD_NOT_ALLOWED StatusCode::METHOD_NOT_ALLOWED
} else { } else {
log::error!("Internal server error in api from {err:?}"); tracing::error!("Internal server error in api from {err:?}");
StatusCode::INTERNAL_SERVER_ERROR StatusCode::INTERNAL_SERVER_ERROR
}; };
let msg = code.canonical_reason().unwrap_or("error"); let msg = code.canonical_reason().unwrap_or("error");
@ -64,7 +64,7 @@ fn login(context: Context, form: LoginForm) -> ApiResult<LoginOk> {
let user = form let user = form
.validate(&db) .validate(&db)
.ok_or_else(|| ApiError::bad_request("login failed"))?; .ok_or_else(|| ApiError::bad_request("login failed"))?;
log::info!("Api login {user:?} ok"); tracing::info!("Api login {user:?} ok");
Ok(LoginOk { Ok(LoginOk {
token: context.make_token(&user)?, token: context.make_token(&user)?,
}) })

View File

@ -4,12 +4,12 @@ use crate::dbopt::{PgPool, PooledPg};
use crate::fetch_places::OverpassOpt; use crate::fetch_places::OverpassOpt;
use crate::photosdir::PhotosDir; use crate::photosdir::PhotosDir;
use diesel::r2d2::{Pool, PooledConnection}; use diesel::r2d2::{Pool, PooledConnection};
use log::{debug, warn};
use medallion::{Header, Payload, Token}; use medallion::{Header, Payload, Token};
use r2d2_memcache::MemcacheConnectionManager; use r2d2_memcache::MemcacheConnectionManager;
use std::future::Future; use std::future::Future;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use tracing::{debug, warn};
use warp::filters::{cookie, header, BoxedFilter}; use warp::filters::{cookie, header, BoxedFilter};
use warp::path::{self, FullPath}; use warp::path::{self, FullPath};
use warp::{self, Filter}; use warp::{self, Filter};

View File

@ -1,7 +1,7 @@
use super::Context; use super::Context;
use crate::photosdir::ImageLoadFailed; use crate::photosdir::ImageLoadFailed;
use crate::templates::{self, RenderError, RenderRucte}; use crate::templates::{self, RenderError, RenderRucte};
use log::{error, warn}; use tracing::{error, warn};
use warp::http::response::Builder; use warp::http::response::Builder;
use warp::http::status::StatusCode; use warp::http::status::StatusCode;
use warp::reply::Response; use warp::reply::Response;

View File

@ -2,8 +2,8 @@ use super::{wrap, BuilderExt, Context, ContextFilter, RenderRucte, Result};
use crate::templates; use crate::templates;
use diesel::prelude::*; use diesel::prelude::*;
use lazy_regex::regex_is_match; use lazy_regex::regex_is_match;
use log::info;
use serde::Deserialize; use serde::Deserialize;
use tracing::info;
use warp::filters::BoxedFilter; use warp::filters::BoxedFilter;
use warp::http::header; use warp::http::header;
use warp::http::response::Builder; use warp::http::response::Builder;

View File

@ -30,10 +30,10 @@ use crate::pidfiles::handle_pid_file;
use crate::templates::{self, Html, RenderRucte}; use crate::templates::{self, Html, RenderRucte};
use chrono::Datelike; use chrono::Datelike;
use diesel::prelude::*; use diesel::prelude::*;
use log::info;
use serde::Deserialize; use serde::Deserialize;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::path::PathBuf; use std::path::PathBuf;
use tracing::info;
use warp::filters::path::Tail; use warp::filters::path::Tail;
use warp::http::{header, response::Builder, StatusCode}; use warp::http::{header, response::Builder, StatusCode};
use warp::reply::Response; use warp::reply::Response;

View File

@ -11,7 +11,7 @@ use crate::templates;
use chrono::{NaiveDate, NaiveDateTime, NaiveTime}; use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
use diesel::pg::PgConnection; use diesel::pg::PgConnection;
use diesel::prelude::*; use diesel::prelude::*;
use log::warn; use tracing::warn;
use warp::http::response::Builder; use warp::http::response::Builder;
use warp::reply::Response; use warp::reply::Response;

View File

@ -5,7 +5,7 @@ use crate::models::{Coord, Photo};
use crate::schema::photos; use crate::schema::photos;
use diesel::pg::{Pg, PgConnection}; use diesel::pg::{Pg, PgConnection};
use diesel::prelude::*; use diesel::prelude::*;
use log::debug; use tracing::debug;
pub fn links_by_time( pub fn links_by_time(
context: &Context, context: &Context,