ddollar / forego

Foreman in Go
1.43k stars 176 forks source link

Get rid of colors in output #92

Closed binfalse closed 7 years ago

binfalse commented 7 years ago

As far as I understand, the outlet always adds color to the output (see https://github.com/ddollar/forego/blob/7a6954ecc44d679b35cab1b6bf08da374c12a67f/outlet.go#L76). That's quite annoying if you want to log the lines to a file, as the file then contains the color codes and becomes hard to read, eg

#033[0m#033[0;33;1mTOOL.1 | #033[0;31;1m2016/10/07 21:36:46 some more output...

Is it possible to get rid of the colors? If not, could you please provide a flag or something?

binfalse commented 7 years ago

I just implemented a proposal at https://github.com/binfalse/forego/tree/strip-output-colors

The latest commit adds a flag --nocolor that disables colour in forego messages: https://github.com/binfalse/forego/commit/1b8d01f4319e08385d28286dffaf5f7a15a11882 What do you guys think?

ddollar commented 7 years ago

Perhaps we could detect whether stdout is a tty and only color in that case? I wonder if we can use termcap somehow...

catmeme commented 7 years ago

Related issue when trying to use graylog: https://github.com/jwilder/nginx-proxy/issues/503

Would appreciate a plugable standard logging format such as syslog or GELF

afefelov commented 7 years ago

Hi guys, I'm using graylog and rsyslog to pass logs into it. I spent up to 4 hours to find out proper solution and finally came with following:

You should add rsyslog conf file like that /etc/rsyslog.d/30-docker.conf:

module(load="mmexternal")
if $syslogtag contains 'nginx' then action(type="mmexternal" binary="/usr/bin/strip_ansi_colors.py" interface.input="msg" )

while /usr/bin/strip_ansi_colors.py looks like:

#! /usr/bin/python

import sys
import re
import json

def onInit():
    """ Do everything that is needed to initialize processing (e.g.
        open files, create handles, connect to systems...)
    """
    pass

def onReceive(msg):
    """This is the entry point where actual work needs to be done. It receives
       the messge from rsyslog and now needs to examine it, do any processing
       necessary. The to-be-modified properties (one or many) need to be pushed
       back to stdout, in JSON format, with no interim line breaks and a line
       break at the end of the JSON. If no field is to be modified, empty
       json ("{}") needs to be emitted.
       Note that no batching takes place (contrary to the output module skeleton)
       and so each message needs to be fully processed (rsyslog will wait for the
       reply before the next message is pushed to this module).
    """
    ansi_escape = re.compile(r'#033[^m]*m') # ansi colors
    msg = ansi_escape.sub('', msg)
    nginx_escape = re.compile(r"\s+nginx.*\|\s+") # duplicating nginx call
    msg = nginx_escape.sub('', msg)
    print json.dumps({'msg': msg})

def onExit():
    """ Do everything that is needed to finish processing (e.g.
        close files, handles, disconnect from systems...). This is
        being called immediately before exiting.
    """
    # most often, nothing to do here

"""
-------------------------------------------------------
This is plumbing that DOES NOT need to be CHANGED
-------------------------------------------------------
Implementor's note: Python seems to very agressively
buffer stdouot. The end result was that rsyslog does not
receive the script's messages in a timely manner (sometimes
even never, probably due to races). To prevent this, we
flush stdout after we have done processing. This is especially
important once we get to the point where the plugin does
two-way conversations with rsyslog. Do NOT change this!
See also: https://github.com/rsyslog/rsyslog/issues/22
"""
onInit()
keepRunning = 1
while keepRunning == 1:
    msg = sys.stdin.readline()
    if msg:
        msg = msg[:-1] # remove LF
        onReceive(msg)
        sys.stdout.flush() # very important, Python buffers far too much!
    else: # an empty line means stdin has been closed
        keepRunning = 0
onExit()
sys.stdout.flush() # very important, Python buffers far too much!

how logs look before:

Mar 11 16:23:26 example.com nginx[15004]: #033[0;36;1mdockergen.1 | #033[0;31;1m2017/03/11 15:23:26 Generated '/etc/nginx/conf.d/default.conf' from 1 containers
Mar 11 18:07:10 example.com nginx[15004]: #033[0;33;1mnginx.1    | #033[0mexample.com 195.255.255.255 - - [11/Mar/2017:17:07:10 +0000] "GET / HTTP/1.1" 503 214 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/602.4.8 (KHTML, like Gecko) Version/10.0.3 Safari/602.4.8"

and now

Mar 11 18:50:49 example.com nginx[15004]: dockergen.1 | 2017/03/11 17:50:49 Contents of /etc/nginx/conf.d/default.conf did not change. Skipping notification 'nginx -s reload'
Mar 11 18:50:51 example.com nginx[15004]: example.com 195.64.208.216 - - [11/Mar/2017:17:50:51 +0000] "GET / HTTP/1.1" 503 214 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/602.4.8 (KHTML, like Gecko) Version/10.0.3 Safari/602.4.8"
ddollar commented 7 years ago

I'm not actively maintaining this project so I'm going to close this issue. I would happily accept a PR that strips the colors for non-tty stdout, though.