I'd love the option to force log messages to span just one line by replacing \n with \\n.
This is an issue which are sometimes encountered when logging Pandas DataFrames and Numpy Arrays.
Hi @AllanLRH.
If you need to customize the line-ending of an handler, you can use a custom format function like this for example:
def my_format(record):
return "[{time}] {function}:{file}:{line} - {message}\\n"
logger.add(sys.stderr, format_my_format)
Thanks, but what I'd really like is an (easy) way to configure the logger to transforn the input as such:
# This is what I want
logger.debug(str(my_numpy_array).replace('\n', '\\n'))
# Perhaps with the option of `repr` instead of `str`
logger.debug(repr(my_numpy_array).replace('\n', '\\n'))
# But I'd love to just write this, and configure the logger to do the work for me :)
logger.debug(my_numpy_array)
I tried looking at the docs for quite a while, but I can't find a straightforward way of doing this.
BTW, Numpy and Pandas arrays are truncated when convert to a string by str, thus preventing the log (or terminal) to be flodded by output.
See example
In [1]: import numpy as np
In [2]: import pandas as pd
In [3]: X = np.random.randint(0, 100, (1000, 5))
In [4]: X
Out[4]:
array([[ 7, 23, 29, 41, 64],
[23, 30, 36, 29, 44],
[61, 94, 31, 60, 45],
...,
[48, 73, 73, 75, 9],
[59, 51, 64, 79, 0],
[19, 74, 58, 27, 89]])
In [5]: df = pd.DataFrame(X)
In [6]: df
Out[6]:
0 1 2 3 4
0 7 23 29 41 64
1 23 30 36 29 44
2 61 94 31 60 45
3 3 57 76 3 10
4 95 89 40 86 63
.. .. .. .. .. ..
995 91 76 15 46 81
996 70 74 66 14 75
997 48 73 73 75 9
998 59 51 64 79 0
999 19 74 58 27 89
[1000 rows x 5 columns]
In [7]: str(X)
Out[7]: '[[ 7 23 29 41 64]\n [23 30 36 29 44]\n [61 94 31 60 45]\n ...\n [48 73 73 75 9]\n [59 51 64 79 0]\n [19 74 58 27 89]]'
In [8]: str(df)
Out[8]: ' 0 1 2 3 4\n0 7 23 29 41 64\n1 23 30 36 29 44\n2 61 94 31 60 45\n3 3 57 76 3 10\n4 95 89 40 86 63\n.. .. .. .. .. ..\n995 91 76 15 46 81\n996 70 74 66 14 75\n997 48 73 73 75 9\n998 59 51 64 79 0\n999 19 74 58 27 89\n\n[1000 rows x 5 columns]'
Oh, yeah, sorry, I completely misinterpreted your question.
So, here is another workaround I can offer you. :smile:
>>> from loguru import logger
>>> multi = "foo\nbar\nbaz\n"
>>> logger.info(multi)
2020-01-11 17:32:33.496 | INFO - __main__ - foo
bar
baz
>>> def flatten_message(record):
... record["message"] = record["message"].replace("\n", "\\n")
...
>>> logger = logger.patch(flatten_message)
>>> logger.info(multi)
2020-01-11 17:33:16.592 | INFO - __main__ - foo\nbar\nbaz\n
I think you can use patch() to force the message to span only one line. You can also apply the change for your whole application by using the patcher parameter of the configure() method.
Sorry to reopen this, but it seems silly to create a new issue... can I patch the messages (or record-dict, I guess) on a sink-level?
Would be nice to force one-line output in files but keep multi-line output in console.
Yep, that's totally possible. Instead of modifying record["message"], just create a new entry to be used by the format parameter of some specific sinks only.
def flatten_message(record):
record["extra"]["flattened_message"] = record["message"].replace("\n", "\\n")
logger.add("file.log", format="[{time}] {extra[flattened_message]}")
logger = logger.patch(flatten_message)
Closing as it seems solved. :+1: