Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Changelog
All notable changes to this project will be documented in this file.

## [2.2.1] - 2025-09-15
- Fixed issue with ANSI exit codes breaking on string interpolation
- Added strip_colour method to String which we now call when sending logs to file
- Added colours/styles: yellow, bg_yellow, bg_white, bg_bright_red, bg_bright_green, bg_bright_blue, bg_bright_magenta, bg_bright_cyan, dim
- Removed colours/styles: bright_black (that's just gray), bright_yellow (that's just yellow), blink (inconsistent/unsupported)
- Added a changelog


## [2.2.0] - 2025-09-08
- Added colourise method to handle colour exist codes
- Added alias for colour/color
- Added alias for brown/yellow
63 changes: 27 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ You can get a logger by calling the following once Herodotus is installed:
logger = DVLA::Herodotus.logger('<system-name>')
```

You can also log out to a file. If you want all the logs in a single file, provide a string of the path to that output file and it will be logged to simultaneously with standard console logger
You can also log out to a file. If you want all the logs in a single file, provide a string of the path to that output file and it will be logged to simultaneously with standard console logger.

**Note:** Log messages are stripped of colour codes before being saved to file.

```ruby
logger = DVLA::Herodotus.logger('<system-name>', output_path: 'logs.txt')
Expand Down Expand Up @@ -82,45 +84,34 @@ logger.new_scenario('Scenario Id')

### Strings

Also included is a series of additional methods on `String` that allow you to modify the colour and style of logs. As these exist on `String`, you can call them on any string such as:
Also included is a series of additional methods on `String` that allow you to modify the colour and style of logs.
You can stack multiple method calls to add additional styling and use string interpolation to style different parts of the string


```ruby
example_string = 'Multicoloured String'.blue.bg_red.bold
example_string = "#{'H'.red}#{'E'.bright_red}#{'R'.yellow}#{'O'.green}#{'D'.blue}#{'O'.bright_blue}#{'T'.magenta}#{'U'.bright_magenta}#{'S'.cyan}".bold.reverse_colour
```

| Method | Function |
|---------------|--------------------------------------------------|
| blue | Sets the string's colour to blue |
| red | Sets the string's colour to red |
| green | Sets the string's colour to green |
| brown | Sets the string's colour to brown |
| blue | Sets the string's colour to blue |
| magenta | Sets the string's colour to magenta |
| cyan | Sets the string's colour to cyan |
| gray | Sets the string's colour to gray |
| grey | Sets the string's colour to grey (alias of gray) |
| bright_blue | Sets the string's colour to bright blue |
| bright_red | Sets the string's colour to bright red |
| bright_green | Sets the string's colour to bright green |
| bright_yellow | Sets the string's colour to bright yellow |
| bright_blue | Sets the string's colour to bright blue |
| bright_magenta| Sets the string's colour to bright magenta |
| bright_cyan | Sets the string's colour to bright cyan |
| white | Sets the string's colour to white |
| bg_blue | Sets the string's background colour to blue |
| bg_red | Sets the string's background colour to red |
| bg_green | Sets the string's background colour to green |
| bg_brown | Sets the string's background colour to brown |
| bg_blue | Sets the string's background colour to blue |
| bg_magenta | Sets the string's background colour to magenta |
| bg_cyan | Sets the string's background colour to cyan |
| bg_gray | Sets the string's background colour to gray |
| bold | Sets the string to be bold |
| italic | Sets the string to be italic |
| underline | Sets the string to be underline |
| blink | Sets the string to blink |
| reverse_color | Reverses the colour of the string |
#### Available String Methods

| Type | Examples |
|------|----------|
| Text Styles | **bold** <span style="opacity:0.6">dim</span> *italic* <u>underline</u> |
| Colors | <span style="color:black">black</span> <span style="color:red">red</span> <span style="color:green">green</span> <span style="color:#B8860B">brown</span> <span style="color:#ffff00">yellow</span> <span style="color:blue">blue</span> <span style="color:magenta">magenta</span> <span style="color:cyan">cyan</span> <span style="color:grey">gray</span> <span style="color:white">white</span> |
| Bright Colors | <span style="color:#ff5555">bright_red</span> <span style="color:#55ff55">bright_green</span> <span style="color:#5555ff">bright_blue</span> <span style="color:#ff55ff">bright_magenta</span> <span style="color:#55ffff">bright_cyan</span> |
| Background Colors | <span style="background:black;color:white">bg_black</span> <span style="background:red;color:white">bg_red</span> <span style="background:green;color:white">bg_green</span> <span style="background:#B8860B;color:white">bg_brown</span> <span style="background:#ffff00;color:black">bg_yellow</span> <span style="background:blue;color:white">bg_blue</span> <span style="background:magenta;color:white">bg_magenta</span> <span style="background:cyan;color:black">bg_cyan</span> <span style="background:grey;color:white">bg_gray</span> <span style="background:white;color:black">bg_white</span> |
| Bright Background Colors | <span style="background:#ff5555;color:white">bg_bright_red</span> <span style="background:#55ff55;color:black">bg_bright_green</span> <span style="background:#5555ff;color:white">bg_bright_blue</span> <span style="background:#ff55ff;color:white">bg_bright_magenta</span> <span style="background:#55ffff;color:black">bg_bright_cyan</span> |
| Utility | strip_colour reverse_colour |

#### To handle differences in spelling the following methods have been given aliases:
| Alias | Original |
|---------------|----------------|
| bg_grey | bg_gray |
| colorize | colourise |
| grey | gray |
| reverse_color | reverse_colour |
| strip_color | strip_colour |

## Development

Herodotus is very lightweight. Currently all code to generate a new logger can be found in `herodotus.rb` and the code for the logger is in `herodotus_logger.rb` so that is the best place to start with any modifications
Herodotus is very lightweight. Currently, all code to generate a new logger can be found in `herodotus.rb` and the code for the logger is in `herodotus_logger.rb` so that is the best place to start with any modifications
9 changes: 8 additions & 1 deletion lib/dvla/herodotus/multi_writer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,14 @@ def initialize(*targets)
end

def write(*args)
@targets.each { |t| t.write(*args) }
@targets.each do |target|
# If we're writing to a file we remove the colour
if target != $stdout && args[0].respond_to?(:strip_colour)
target.write(args[0].strip_colour, *args[1..])
else
target.write(*args)
end
end
end

def close
Expand Down
68 changes: 58 additions & 10 deletions lib/dvla/herodotus/string.rb
Original file line number Diff line number Diff line change
@@ -1,43 +1,91 @@
class String
def colourise(code, reset_code = 39)
"\e[#{code}m#{self}\e[#{reset_code}m"
# Making sure we align the correct reset codes
if self.include?("\e[#{reset_code}m")
result = self.gsub("\e[#{reset_code}m", "\e[#{reset_code}m\e[#{code}m")
"\e[#{code}m#{result}\e[#{reset_code}m"
else
"\e[#{code}m#{self}\e[#{reset_code}m"
end
end
alias colorize colourise

def white = colourise(97)

def black = colourise(30)

def red = colourise(31)

def green = colourise(32)

def brown = colourise(33)
alias yellow brown

def yellow = colourise(93)

def blue = colourise(34)

def magenta = colourise(35)

def cyan = colourise(36)

def gray = colourise(37)
alias grey gray

def bright_black = colourise(90)
def bright_red = colourise(91)

def bright_green = colourise(92)
def bright_yellow = colourise(93)

def bright_blue = colourise(94)

def bright_magenta = colourise(95)

def bright_cyan = colourise(96)
def white = colourise(97)

def bg_black = colourise(40, 49)

def bg_red = colourise(41, 49)

def bg_green = colourise(42, 49)

def bg_brown = colourise(43, 49)

def bg_yellow = colourise(103, 49)

def bg_blue = colourise(44, 49)

def bg_magenta = colourise(45, 49)

def bg_cyan = colourise(46, 49)

def bg_gray = colourise(47, 49)

def bg_white = colourise(107, 49)

def bg_bright_red = colourise(101, 49)

def bg_bright_green = colourise(102, 49)

def bg_bright_blue = colourise(104, 49)

def bg_bright_magenta = colourise(105, 49)

def bg_bright_cyan = colourise(106, 49)

def bold = colourise(1, 22)

def dim = colourise(2, 22)

def italic = colourise(3, 23)

def underline = colourise(4, 24)
def blink = colourise(5, 25)
def reverse_color = colourise(7, 27)
alias reverse_colour reverse_color

def reverse_colour = colourise(7, 27)

def strip_colour
gsub(/\e\[[0-9;]*m/, '')
end

alias bg_grey bg_gray
alias colorize colourise
alias grey gray
alias reverse_color reverse_colour
alias strip_color strip_colour
end
2 changes: 1 addition & 1 deletion lib/dvla/herodotus/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module DVLA
module Herodotus
VERSION = '2.2.0'.freeze
VERSION = '2.2.1'.freeze
end
end
12 changes: 12 additions & 0 deletions spec/dvla/herodotus/multi_writer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,16 @@

expect($stdout.closed?).to be false
end

it 'strips colours from messages when writing to non-stdout targets' do
file_output = StringIO.new
coloured_message = 'test message'.red.underline.bg_blue

allow($stdout).to receive(:write)

multi_writer = DVLA::Herodotus::MultiWriter.new($stdout, file_output)
multi_writer.write(coloured_message)

expect(file_output.string).to eq('test message')
end
end
48 changes: 41 additions & 7 deletions spec/dvla/herodotus/string_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,72 @@
{ method: :red, expected_output: "\e[31mTest String\e[39m" },
{ method: :green, expected_output: "\e[32mTest String\e[39m" },
{ method: :brown, expected_output: "\e[33mTest String\e[39m" },
{ method: :yellow, expected_output: "\e[33mTest String\e[39m" },
{ method: :yellow, expected_output: "\e[93mTest String\e[39m" },
{ method: :blue, expected_output: "\e[34mTest String\e[39m" },
{ method: :magenta, expected_output: "\e[35mTest String\e[39m" },
{ method: :cyan, expected_output: "\e[36mTest String\e[39m" },
{ method: :gray, expected_output: "\e[37mTest String\e[39m" },
{ method: :grey, expected_output: "\e[37mTest String\e[39m" },
{ method: :bright_black, expected_output: "\e[90mTest String\e[39m" },
{ method: :white, expected_output: "\e[97mTest String\e[39m" },
{ method: :bright_red, expected_output: "\e[91mTest String\e[39m" },
{ method: :bright_green, expected_output: "\e[92mTest String\e[39m" },
{ method: :bright_yellow, expected_output: "\e[93mTest String\e[39m" },
{ method: :bright_blue, expected_output: "\e[94mTest String\e[39m" },
{ method: :bright_magenta, expected_output: "\e[95mTest String\e[39m" },
{ method: :bright_cyan, expected_output: "\e[96mTest String\e[39m" },
{ method: :white, expected_output: "\e[97mTest String\e[39m" },
{ method: :bg_black, expected_output: "\e[40mTest String\e[49m" },
{ method: :bg_red, expected_output: "\e[41mTest String\e[49m" },
{ method: :bg_green, expected_output: "\e[42mTest String\e[49m" },
{ method: :bg_brown, expected_output: "\e[43mTest String\e[49m" },
{ method: :bg_yellow, expected_output: "\e[103mTest String\e[49m" },
{ method: :bg_blue, expected_output: "\e[44mTest String\e[49m" },
{ method: :bg_magenta, expected_output: "\e[45mTest String\e[49m" },
{ method: :bg_cyan, expected_output: "\e[46mTest String\e[49m" },
{ method: :bg_gray, expected_output: "\e[47mTest String\e[49m" },
{ method: :bg_white, expected_output: "\e[107mTest String\e[49m" },
{ method: :bg_bright_red, expected_output: "\e[101mTest String\e[49m" },
{ method: :bg_bright_green, expected_output: "\e[102mTest String\e[49m" },
{ method: :bg_bright_blue, expected_output: "\e[104mTest String\e[49m" },
{ method: :bg_bright_magenta, expected_output: "\e[105mTest String\e[49m" },
{ method: :bg_bright_cyan, expected_output: "\e[106mTest String\e[49m" },
{ method: :bold, expected_output: "\e[1mTest String\e[22m" },
{ method: :dim, expected_output: "\e[2mTest String\e[22m" },
{ method: :italic, expected_output: "\e[3mTest String\e[23m" },
{ method: :underline, expected_output: "\e[4mTest String\e[24m" },
{ method: :blink, expected_output: "\e[5mTest String\e[25m" },
{ method: :reverse_color, expected_output: "\e[7mTest String\e[27m" },
{ method: :reverse_colour, expected_output: "\e[7mTest String\e[27m" },
].each do |testcase|
it 'applies the expected formatting to a string' do
result = 'Test String'.send(testcase[:method])

expect(result).to eq(testcase[:expected_output])
end
end

describe 'strip_colour' do
it 'removes ANSI colour codes from strings' do
coloured_string = "\e[31m\e[1mRed Bold Text\e[22m\e[39m"
expect(coloured_string.strip_colour).to eq('Red Bold Text')
end

it 'handles complex nested colours' do
complex_string = "\e[31mRed \e[32mGreen\e[39m Red Again\e[39m"
expect(complex_string.strip_colour).to eq('Red Green Red Again')
end
end

describe 'colour combinations' do
it 'chains multiple styles correctly' do
expect('Test'.red.bold.underline).to eq "\e[4m\e[1m\e[31mTest\e[39m\e[22m\e[24m"
end

it 'combines foreground and background colours' do
expect('Test'.white.bg_red).to eq "\e[41m\e[97mTest\e[39m\e[49m"
end

it 'handles bright colours with styles' do
expect('Test'.bright_blue.bold.italic).to eq "\e[3m\e[1m\e[94mTest\e[39m\e[22m\e[23m"
end

it 'works with reverse and other styles' do
expect('Test'.red.bg_yellow.reverse_colour.bold).to eq "\e[1m\e[7m\e[103m\e[31mTest\e[39m\e[49m\e[27m\e[22m"
end
end
end