rust 44 lines · 9 steps

Redacting sensitive data from logs in Rust

Compile regexes once and validate credit card matches with the Luhn checksum before masking them out of log text.

Explained by highlit
1use once_cell::sync::Lazy;
2use regex::Regex;
3 
4static CREDIT_CARD: Lazy<Regex> = Lazy::new(|| {
5 Regex::new(r"\b(?:\d[ -]*?){13,16}\b").unwrap()
6});
7 
8static SSN: Lazy<Regex> = Lazy::new(|| {
9 Regex::new(r"\b\d{3}-\d{2}-\d{4}\b").unwrap()
10});
11 
12fn luhn_valid(candidate: &str) -> bool {
13 let digits: Vec<u32> = candidate.chars().filter_map(|c| c.to_digit(10)).collect();
14 if !(13..=16).contains(&digits.len()) {
15 return false;
16 }
17 let sum: u32 = digits
18 .iter()
19 .rev()
20 .enumerate()
21 .map(|(i, &d)| {
22 if i % 2 == 1 {
23 let doubled = d * 2;
24 if doubled > 9 { doubled - 9 } else { doubled }
25 } else {
26 d
27 }
28 })
29 .sum();
30 sum % 10 == 0
31}
32 
33pub fn redact(log: &str) -> String {
34 let cc_masked = CREDIT_CARD.replace_all(log, |caps: &regex::Captures| {
35 let matched = &caps[0];
36 if luhn_valid(matched) {
37 "[REDACTED-CC]".to_string()
38 } else {
39 matched.to_string()
40 }
41 });
42 
43 SSN.replace_all(&cc_masked, "[REDACTED-SSN]").into_owned()
44}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Lazy statics let you compile expensive resources like regexes exactly once and share them safely.
  2. 2A structural regex match isn't proof of a real value — pairing it with a checksum like Luhn cuts false positives.
  3. 3Passing a closure to replace_all lets each match be inspected and conditionally transformed.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Redacting sensitive data from logs in Rust — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code