Skip to content

Commit da0b323

Browse files
authored
Merge pull request Supervisor#1235 from vsajip/fix-1231
Initial cut for fix of issue Supervisor#1231
2 parents 6bd04b6 + e17d2fc commit da0b323

File tree

6 files changed

+108
-4
lines changed

6 files changed

+108
-4
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
*~
2-
*.conf
32
*.egg
43
*.egg-info
54
*.log

supervisor/http_client.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,23 @@ def done(self, url):
2929

3030
def feed(self, url, data):
3131
try:
32-
data = as_string(data)
32+
sdata = as_string(data)
3333
except UnicodeDecodeError:
34-
data = 'Undecodable: %r' % data
35-
sys.stdout.write(data)
34+
sdata = 'Undecodable: %r' % data
35+
# We've got Unicode data in sdata now, but writing to stdout sometimes
36+
# fails - see issue #1231.
37+
try:
38+
sys.stdout.write(sdata)
39+
except UnicodeEncodeError as e:
40+
if sys.version_info[0] < 3:
41+
# This might seem like The Wrong Thing To Do (writing bytes
42+
# rather than text to an output stream), but it seems to work
43+
# OK for Python 2.7.
44+
sys.stdout.write(data)
45+
else:
46+
s = ('Unable to write Unicode to stdout because it has '
47+
'encoding %s' % sys.stdout.encoding)
48+
raise ValueError(s)
3649
sys.stdout.flush()
3750

3851
def close(self, url):

supervisor/supervisorctl.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,14 @@ class DefaultControllerPlugin(ControllerPluginBase):
440440
name = 'default'
441441
listener = None # for unit tests
442442
def _tailf(self, path):
443+
def not_all_langs():
444+
enc = getattr(sys.stdout, 'encoding', '').lower()
445+
return None if enc.startswith('utf') else sys.stdout.encoding
446+
447+
problematic_enc = not_all_langs()
448+
if problematic_enc:
449+
self.ctl.output('Warning: sys.stdout.encoding is set to %s, so '
450+
'Unicode output may fail.' % problematic_enc)
443451
self.ctl.output('==> Press Ctrl-C to exit <==')
444452

445453
username = self.ctl.options.username
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[supervisord]
2+
loglevel=info ; log level; default info; others: debug,warn,trace
3+
logfile=/tmp/issue-1231.log ; main log file; default $CWD/supervisord.log
4+
pidfile=/tmp/issue-1231.pid ; supervisord pidfile; default supervisord.pid
5+
nodaemon=true ; start in foreground if true; default false
6+
7+
[rpcinterface:supervisor]
8+
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
9+
10+
[unix_http_server]
11+
file=/tmp/issue-1231.sock ; the path to the socket file
12+
13+
[supervisorctl]
14+
serverurl=unix:///tmp/issue-1231.sock ; use a unix:// URL for a unix socket
15+
16+
[program:hello]
17+
command=python %(here)s/test_1231.py
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# -*- coding: utf-8 -*-
2+
import logging
3+
import random
4+
import sys
5+
import time
6+
7+
def main():
8+
logging.basicConfig(level=logging.INFO, stream=sys.stdout,
9+
format='%(levelname)s [%(asctime)s] %(message)s',
10+
datefmt='%m-%d|%H:%M:%S')
11+
i = 1
12+
while True:
13+
delay = random.randint(400, 1200)
14+
time.sleep(delay / 1000.0)
15+
logging.info('%d - hash=57d94b…381088', i)
16+
i += 1
17+
18+
if __name__ == '__main__':
19+
main()

supervisor/tests/test_end_to_end.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,54 @@ def test_issue_1224(self):
136136
self.addCleanup(supervisord.kill, signal.SIGINT)
137137
supervisord.expect_exact('cat entered RUNNING state', timeout=60)
138138

139+
def test_issue_1231a(self):
140+
filename = pkg_resources.resource_filename(__name__, 'fixtures/issue-1231.conf')
141+
args = ['-m', 'supervisor.supervisord', '-c', filename]
142+
supervisord = pexpect.spawn(sys.executable, args, encoding='utf-8')
143+
self.addCleanup(supervisord.kill, signal.SIGINT)
144+
supervisord.expect_exact('success: hello entered RUNNING state')
145+
146+
args = ['-m', 'supervisor.supervisorctl', '-c', filename, 'tail', '-f', 'hello']
147+
supervisorctl = pexpect.spawn(sys.executable, args, encoding='utf-8')
148+
self.addCleanup(supervisorctl.kill, signal.SIGINT)
149+
150+
for i in range(1, 4):
151+
line = '%d - hash=57d94b…381088' % i
152+
supervisorctl.expect_exact(line, timeout=30)
153+
154+
155+
def test_issue_1231b(self):
156+
filename = pkg_resources.resource_filename(__name__, 'fixtures/issue-1231.conf')
157+
args = ['-m', 'supervisor.supervisord', '-c', filename]
158+
supervisord = pexpect.spawn(sys.executable, args, encoding='utf-8')
159+
self.addCleanup(supervisord.kill, signal.SIGINT)
160+
supervisord.expect_exact('success: hello entered RUNNING state')
161+
162+
args = ['-m', 'supervisor.supervisorctl', '-c', filename, 'tail', '-f', 'hello']
163+
env = os.environ.copy()
164+
env['LANG'] = 'oops'
165+
supervisorctl = pexpect.spawn(sys.executable, args, encoding='utf-8',
166+
env=env)
167+
self.addCleanup(supervisorctl.kill, signal.SIGINT)
168+
169+
# For Python 3 < 3.7, LANG=oops leads to warnings because of the
170+
# stdout encoding. For 3.7 (and presumably later), the encoding is
171+
# utf-8 when LANG=oops.
172+
if sys.version_info[:2] < (3, 7):
173+
supervisorctl.expect('Warning: sys.stdout.encoding is set to ',
174+
timeout=30)
175+
supervisorctl.expect('Unicode output may fail.', timeout=30)
176+
177+
for i in range(1, 4):
178+
line = '%d - hash=57d94b…381088' % i
179+
try:
180+
supervisorctl.expect_exact(line, timeout=30)
181+
except pexpect.exceptions.EOF:
182+
self.assertIn('Unable to write Unicode to stdout because it '
183+
'has encoding ',
184+
supervisorctl.before)
185+
break
186+
139187

140188
def test_suite():
141189
return unittest.findTestCases(sys.modules[__name__])

0 commit comments

Comments
 (0)