Skip to content

feat(new transform): Add ansi stripper transform#1188

Merged
lukesteensen merged 1 commit intovectordotdev:masterfrom
JeanMertz:ansi-stripper
Nov 19, 2019
Merged

feat(new transform): Add ansi stripper transform#1188
lukesteensen merged 1 commit intovectordotdev:masterfrom
JeanMertz:ansi-stripper

Conversation

@JeanMertz
Copy link
Copy Markdown
Contributor

@JeanMertz JeanMertz commented Nov 14, 2019

Given a log field with ansi escape sequences such as:

\x1b[32mhello\x1b[m world

The escape sequences are stripped from the string:

hello world

This transformer only works on string-type fields, any other field type
will result in a warning and an unchanged value.


This does not yet add any documentation, or changes any benchmarks or integration tests.

Closes #908

Given a log field with ansi escape sequences such as:

    \x1b[32mhello\x1b[m world

The escape sequences are stripped from the string:

    hello world

This transformer only works on string-type fields, any other field type
will result in a warning and an unchanged value.

Signed-off-by: Jean Mertz <jean@mertz.fm>
owning_ref = "0.4.0"
listenfd = "0.3.3"
inventory = "0.1"
strip-ansi-escapes = "0.1.0"
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not sure if we want to add this dependency. It adds a minimal amount of extra dependencies, and it gets the job done.

Alternatively, we could do the escape sequence parsing ourselves, but it's a bit more complex than writing a simple regular expression, so we'd probably want to write a tiny parser if we go that route.

Another option would be to simplify the implementation and only account for the most common "CSI" escape sequence patterns.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This definitely seems worthwhile to me, especially as a pretty light dependency.

field = self.field.as_ref(),
),
Some(ValueKind::Bytes(ref mut bytes)) => {
*bytes = match strip_ansi_escapes::strip(bytes.clone()) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

A downside to this is that the clone happens for all strings, even those that don't have any escape sequences.

One (initial) solution could be to match the bytes for the \x1b[ pattern and only then strip escape sequences, but that would only cover a subset of possible escape sequences.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this is a good place to start. Down the line, if there's a need for more performance, we can make a pass at profiling and optimizing.


#[test]
fn ansi_stripper_transform() {
assert_foo_bar![
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This tests all potential escape sequences as described in http://ascii-table.com/ansi-escape-sequences.php.

@lukesteensen lukesteensen self-requested a review November 14, 2019 22:25
@binarylogic
Copy link
Copy Markdown
Contributor

Very nice! This looks great.

@binarylogic binarylogic changed the title feat(new transform): add ansi stripper transform feat(new transform): Add ansi stripper transform Nov 16, 2019
Copy link
Copy Markdown
Member

@lukesteensen lukesteensen left a comment

Choose a reason for hiding this comment

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

Looks great, thank you!

owning_ref = "0.4.0"
listenfd = "0.3.3"
inventory = "0.1"
strip-ansi-escapes = "0.1.0"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This definitely seems worthwhile to me, especially as a pretty light dependency.

field = self.field.as_ref(),
),
Some(ValueKind::Bytes(ref mut bytes)) => {
*bytes = match strip_ansi_escapes::strip(bytes.clone()) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this is a good place to start. Down the line, if there's a need for more performance, we can make a pass at profiling and optimizing.

@lukesteensen lukesteensen merged commit 2d419d5 into vectordotdev:master Nov 19, 2019
@huyz
Copy link
Copy Markdown

huyz commented Aug 4, 2025

How do we use it? can't find it listed here: https://vector.dev/docs/reference/configuration/transforms/

@pront
Copy link
Copy Markdown
Member

pront commented Aug 4, 2025

How do we use it? can't find it listed here: vector.dev/docs/reference/configuration/transforms

This not listed on the website because the transform was deleted. I would use remap and https://vector.dev/docs/reference/vrl/functions/#strip_ansi_escape_codes

@huyz
Copy link
Copy Markdown

huyz commented Aug 4, 2025

@pront Perfect, thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

New ansi_stripper transform

5 participants