[READ-ONLY] Mirror of https://github.com/FoxxMD/docker-proxy-filter. Filter the contents of Docker API responses
docker docker-socket-proxy filter
0

Configure Feed

Select the types of activity you want to include in your feed.

feat: log tracing using spans for better visibility into requests

FoxxMD (Oct 9, 2025, 7:10 PM UTC) 756f790b 4cf6c4db

+32 -15
+3 -4
src/docker.rs
··· 33 33 if filter_names.is_empty() && filter_labels.is_empty() { 34 34 return true 35 35 } 36 - let mut any = false; 37 36 if !filter_names.is_empty() { 38 37 if utils::strings_in_strings(&names, &filter_names) { 39 - any = true; 38 + return true; 40 39 } 41 40 } 42 41 if !filter_labels.is_empty() { 43 42 if utils::label_match(&labels, &filter_labels) { 44 - any = true; 43 + return true; 45 44 } 46 45 } 47 - any 46 + false 48 47 } 49 48 50 49 pub fn container_summary_match(container: &types::ContainerSummary, container_names: &ContainerNames, container_labels: &ContainerLabels) -> bool {
+1
src/main.rs
··· 1 + use tracing::*; 1 2 use ntex::{http, web::{self}}; 2 3 use std::sync::{Arc, Mutex}; 3 4
+16 -7
src/proxy.rs
··· 7 7 8 8 use crate::config::{AppConfig}; 9 9 use crate::docker::{self, types::*}; 10 + use crate::utils; 10 11 11 12 #[derive(Clone)] 12 13 pub struct AppStateWithContainerMap { ··· 43 44 44 45 // if route is to list containers we want to return a filtered list 45 46 if new_url.path().contains("containers/json") { 47 + let _list_span = span!(Level::DEBUG, "Container List").entered(); 46 48 47 49 let containers = &res.json::<Vec<ContainerSummary>>().await.unwrap(); 48 50 49 51 // filter all containers to only those that have values from CONTAINER_NAMES includes in their names 50 52 let filtered_containers = containers.into_iter() 51 - .filter(|&con| docker::container_summary_match(con, &app_config.get_ref().container_names, &app_config.get_ref().container_labels)) 53 + .filter(|&con| { 54 + let _list_span = span!(Level::DEBUG, "Container", id = utils::short_id(con.id.as_ref().unwrap())).entered(); 55 + docker::container_summary_match(con, &app_config.get_ref().container_names, &app_config.get_ref().container_labels) 56 + }) 52 57 .collect::<Vec<&ContainerSummary>>(); 53 58 54 59 let fresp = web::HttpResponse::build(res.status()).json(&filtered_containers); ··· 59 64 // only deal with routes that are for containers like /containers/1234/{some_resource} 60 65 match docker::match_container_get(new_url.path()) { 61 66 // the regex pulls the container id from the route with a named capture group, avaiable as m.id 67 + 62 68 Some (m) => { 69 + let short_cid = utils::short_id(&m.id); //format!("{start}...{end}", start = &m.id[..6], end = &m.id[&m.id.len() - 6..]); 70 + let _con_span = span!(Level::DEBUG, "Container", id = short_cid).entered(); 71 + debug!("Matched container route with Id {}", &m.id); 63 72 // we keep a stateful hashmap of all requested container ids and their names 64 73 // see AppStateWithContainerMap 65 74 let mut cm = data.container_map.lock().unwrap(); ··· 67 76 // if the map does not already include the container id-name then we try to get it with our own request to docker api 68 77 // or if we encountered an error last time then try again 69 78 if !cm.contains_key(&m.id) || cm.get(&m.id).unwrap().is_none() { 70 - debug!("Requested container Id not in map, trying to inspect: {}", &m.id); 79 + debug!("Requested Id not in map, trying to inspect..."); 71 80 let info_res = docker::get_container_info(&forward_url.to_string(), &m.id).await; 72 81 match info_res { 73 82 Ok((name, labels)) => { 74 83 let is_container_match = docker::match_labels_or_names(&app_config.get_ref().container_names, &app_config.get_ref().container_labels, &Vec::from([name.clone()]), &labels); 75 - debug!("Container Id {} with name '{}' {} valid", &m.id, name, is!(is_container_match; "is";"is not")); 84 + debug!("Recording container '{}' {} valid", name, is!(is_container_match; "as";"as not")); 76 85 cm.insert(m.id.clone(), Some(is_container_match)); 77 86 } 78 87 Err(e) => { 79 - warn!("Could not inspect container {}: {e}", &m.id); 88 + warn!("Could not inspect: {e}"); 80 89 if e.to_string().contains("No such container") { 81 90 cm.insert(m.id.clone(), Some(false)); 82 91 } else { ··· 94 103 Some(n) => { 95 104 // only return if a response if requested container has a name that includes values from CONTAINER_NAMES 96 105 if *n { 97 - 106 + debug!("Matched container filters"); 98 107 // if the route resource is specifically the Container Inspect API 99 108 // then we may need to scrub Envs if SCRUB_ENVS=true 100 109 if m.resource == "json" { ··· 114 123 Ok(client_resp.streaming(res.into_stream())) 115 124 } 116 125 } else { 117 - debug!("Container {} does not match container filters, 404ing...", &m.id); 126 + debug!("Does not match container filters, 404ing..."); 118 127 client_resp.status(StatusCode::NOT_FOUND); 119 128 Ok(client_resp.json(&DockerErrorMessage { message: format!("No such container: {}", &m.id)})) 120 129 } 121 130 } 122 131 None => { 123 - debug!("Container {} does not exist or Docker API previously returned an error, 404ing...", &m.id); 132 + debug!("Does not exist or Docker API previously returned an error, 404ing..."); 124 133 client_resp.status(StatusCode::NOT_FOUND); 125 134 Ok(client_resp.json(&DockerErrorMessage { message: format!("No such container: {}", &m.id)})) 126 135 }
+12 -4
src/utils.rs
··· 1 1 use crate::config::ContainerLabels; 2 + use core::num; 2 3 use std::collections::HashMap; 3 4 use tracing::*; 4 5 5 6 pub fn strings_in_strings(ref_strings: &Vec<String>, contains_strings: &Vec<String>) -> bool { 6 - let matched_str = ref_strings.iter().find(|x| contains_strings.iter().any(|y| x.contains(y))); 7 - if matched_str.is_some() { 8 - debug!("One of '{}' found in {}", contains_strings.join(","), matched_str.unwrap()); 9 - } 7 + let matched_str = ref_strings.iter().find(|x| contains_strings.iter().any(|y| { 8 + let contains = x.contains(y); 9 + if contains { 10 + debug!("'{}' found in {}", y, x); 11 + } 12 + contains 13 + })); 10 14 11 15 matched_str.is_some() 12 16 } ··· 44 48 } 45 49 46 50 return false 51 + } 52 + 53 + pub fn short_id(s: &String) -> String { 54 + return format!("{start}...{end}", start = &s[..6], end = &s[s.len() - 6..]); 47 55 }