Skip to content
This repository was archived by the owner on Dec 8, 2020. It is now read-only.

Commit 9e46661

Browse files
Merge pull request #43 from timberio/features/36-escape-new-lines-heroku
Escape newlines with Heroku
2 parents 55f2193 + d03072f commit 9e46661

File tree

1 file changed

+40
-3
lines changed

1 file changed

+40
-3
lines changed

lib/timber/transports/io_device.ex

+40-3
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,20 @@ defmodule Timber.Transports.IODevice do
6262
6363
_Defaults to `true`._
6464
65+
#### `escape_new_lines`
66+
67+
When `true`, new lines characters are escaped as `\\n`.
68+
69+
When `false`, new lines characters are left alone.
70+
71+
This circumvents issues with output devices (like Heroku Logplex) that will tranform
72+
line breaks into multiple log lines.
73+
74+
When the IODevice transport is initialized, it will check for the environment
75+
variable `HEROKU`. If the environment variable is present, this will be set to
76+
`true`. Otherwise, this defaults to `false`. Setting the value in your application
77+
configuration will always override the initialized setting..
78+
6579
#### `format`
6680
6781
Determines the output format to use. Even though the Timber service is designed
@@ -134,6 +148,7 @@ defmodule Timber.Transports.IODevice do
134148

135149
@default_colorize true
136150
@default_max_buffer_size 100
151+
@default_escape_new_lines false
137152
@default_format :json
138153
@default_print_log_level false
139154
@default_print_metadata true
@@ -147,6 +162,7 @@ defmodule Timber.Transports.IODevice do
147162
buffer_size: non_neg_integer,
148163
max_buffer_size: pos_integer,
149164
colorize: boolean,
165+
escape_new_lines: boolean,
150166
format: :json | :logfmt,
151167
print_log_level: boolean,
152168
print_metadata: boolean,
@@ -159,6 +175,7 @@ defmodule Timber.Transports.IODevice do
159175
output: nil,
160176
buffer_size: 0,
161177
colorize: @default_colorize,
178+
escape_new_lines: @default_escape_new_lines,
162179
format: @default_format,
163180
max_buffer_size: @default_max_buffer_size,
164181
print_log_level: @default_print_log_level,
@@ -181,7 +198,14 @@ defmodule Timber.Transports.IODevice do
181198
# configuration
182199
@spec get_init_config() :: Keyword.t
183200
defp get_init_config() do
184-
Application.get_env(:timber, :io_device, [])
201+
heroku_env = System.get_env("HEROKU")
202+
heroku? = !is_nil(heroku_env)
203+
204+
init_env = [escape_new_lines: heroku?]
205+
206+
env = Application.get_env(:timber, :io_device, [])
207+
208+
Keyword.merge(init_env, env)
185209
end
186210

187211
@spec get_device(String.t | :no_file) :: {:ok, IO.device} | {:error, Exception.t}
@@ -214,6 +238,7 @@ defmodule Timber.Transports.IODevice do
214238
@spec configure(Keyword.t, t) :: {:ok, t}
215239
def configure(options, state) do
216240
colorize = Keyword.get(options, :colorize, @default_colorize)
241+
escape_new_lines = Keyword.get(options, :escape_new_lines, @default_escape_new_lines)
217242
format = Keyword.get(options, :format, @default_format)
218243
max_buffer_size = Keyword.get(options, :max_buffer_size, @default_max_buffer_size)
219244
print_log_level = Keyword.get(options, :print_log_level, @default_print_log_level)
@@ -222,6 +247,7 @@ defmodule Timber.Transports.IODevice do
222247

223248
new_state = %{ state |
224249
colorize: colorize,
250+
escape_new_lines: escape_new_lines,
225251
format: format,
226252
max_buffer_size: max_buffer_size,
227253
print_log_level: print_log_level,
@@ -251,10 +277,14 @@ defmodule Timber.Transports.IODevice do
251277
[]
252278
end
253279

254-
output =
255-
[message, metadata, "\n"]
280+
line_output =
281+
[message, metadata]
256282
|> add_log_level(level_b, state.print_log_level)
257283
|> add_timestamp(timestamp, state.print_timestamps)
284+
|> escape_new_lines(state.escape_new_lines)
285+
286+
# Prevents the final new line from being escaped
287+
output = [line_output, ?\n]
258288

259289
cond do
260290
is_nil(ref) ->
@@ -308,6 +338,13 @@ defmodule Timber.Transports.IODevice do
308338
defp log_level_color(:error), do: :red
309339
defp log_level_color(_), do: :normal
310340

341+
@spec escape_new_lines(IO.chardata, boolean) :: IO.chardata
342+
defp escape_new_lines(msg, false), do: msg
343+
defp escape_new_lines(msg, true) do
344+
to_string(msg)
345+
|> String.replace(<< ?\n :: utf8 >>, << ?\\ :: utf8, ?n :: utf8 >>)
346+
end
347+
311348
@spec write_buffer(IO.chardata, t) :: t
312349
defp write_buffer(output, state) do
313350
buffer = state.buffer

0 commit comments

Comments
 (0)