Skip to content
This repository was archived by the owner on May 23, 2023. It is now read-only.

Commit a98b360

Browse files
committed
Fix json-logging regression
(Properly) json-formatted logging got lost somewhere in the process of factoring out the `structlog` dependency. This commit (re)enables json formatted kwargs when logging is configured with `log_json=True`. related to #327 since the bug investigation is facilitated by machine- readable vm traces.
1 parent f1cf0fa commit a98b360

File tree

4 files changed

+59
-20
lines changed

4 files changed

+59
-20
lines changed

ethereum/processblock.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,27 @@ def rp(what, actual, target):
108108
return True
109109

110110

111+
class lazy_safe_encode(object):
112+
"""Creates a lazy and logging safe representation of transaction data.
113+
Use this in logging of transactions; instead of
114+
115+
>>> log.debug(data=data)
116+
117+
do this:
118+
119+
>>> log.debug(data=lazy_safe_encode(data))
120+
"""
121+
122+
def __init__(self, data):
123+
self.data = data
124+
125+
def __str__(self):
126+
if not isinstance(self.data, (str, unicode)):
127+
return self.data
128+
else:
129+
return encode_hex(self.data)
130+
131+
111132
def apply_transaction(block, tx):
112133
validate_transaction(block, tx)
113134

@@ -139,16 +160,16 @@ def rp(what, actual, target):
139160
ext = VMExt(block, tx)
140161
if tx.to and tx.to != CREATE_CONTRACT_ADDRESS:
141162
result, gas_remained, data = apply_msg(ext, message)
142-
log_tx.debug('_res_', result=result, gas_remained=gas_remained, data=data)
163+
log_tx.debug('_res_', result=result, gas_remained=gas_remained, data=lazy_safe_encode(data))
143164
else: # CREATE
144165
result, gas_remained, data = create_contract(ext, message)
145166
assert utils.is_numeric(gas_remained)
146-
log_tx.debug('_create_', result=result, gas_remained=gas_remained, data=data)
167+
log_tx.debug('_create_', result=result, gas_remained=gas_remained, data=lazy_safe_encode(data))
147168

148169
assert gas_remained >= 0
149170

150171
log_tx.debug("TX APPLIED", result=result, gas_remained=gas_remained,
151-
data=data)
172+
data=lazy_safe_encode(data))
152173

153174
if not result: # 0 = OOG failure in both cases
154175
log_tx.debug('TX FAILED', reason='out of gas',
@@ -158,7 +179,7 @@ def rp(what, actual, target):
158179
output = b''
159180
success = 0
160181
else:
161-
log_tx.debug('TX SUCCESS', data=data)
182+
log_tx.debug('TX SUCCESS', data=lazy_safe_encode(data))
162183
gas_used = tx.startgas - gas_remained
163184
block.refunds += len(set(block.suicides)) * opcodes.GSUICIDEREFUND
164185
if block.refunds > 0:

ethereum/slogging.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ def get_configuration():
8585

8686
config_string = ','.join('%s:%s' % x for x in name_levels)
8787

88-
return dict(config_string=config_string, log_json=root.log_json)
88+
return dict(config_string=config_string, log_json=SLogger.manager.log_json)
8989

9090

9191
def get_logger_names():
@@ -121,17 +121,22 @@ def __init__(self, name, level=DEFAULT_LOGLEVEL):
121121
self.warn = self.warning
122122
super(SLogger, self).__init__(name, level=level)
123123

124+
@property
125+
def log_json(self):
126+
return SLogger.manager.log_json
127+
124128
def is_active(self, level_name='trace'):
125129
return self.isEnabledFor(logging._checkLevel(level_name.upper()))
126130

127-
def format_message(self, msg, kwargs, highlight):
131+
def format_message(self, msg, kwargs, highlight, level):
128132
if getattr(self, 'log_json', False):
129133
message = {
130134
k: v if isnumeric(v) or isinstance(v, (float, complex)) else repr(v)
131135
for k, v in kwargs.items()
132136
}
133137

134-
message['event'] = "{}.{}".format(self.name, msg)
138+
message['event'] = '{}.{}'.format(self.name, msg.lower().replace(' ', '_'))
139+
message['level'] = logging.getLevelName(level)
135140
msg = json.dumps(message)
136141
else:
137142
msg = "{}{} {}{}".format(
@@ -140,7 +145,6 @@ def format_message(self, msg, kwargs, highlight):
140145
" ".join("{}={!s}".format(k, v) for k, v in kwargs.items()),
141146
bcolors.ENDC if highlight else ""
142147
)
143-
144148
return msg
145149

146150
def bind(self, **kwargs):
@@ -152,7 +156,7 @@ def _log(self, level, msg, args, **kwargs):
152156
highlight = kwargs.pop('highlight', False)
153157
extra['kwargs'] = kwargs
154158
extra['original_msg'] = msg
155-
msg = self.format_message(msg, kwargs, highlight)
159+
msg = self.format_message(msg, kwargs, highlight, level)
156160
super(SLogger, self)._log(level, msg, args, exc_info, extra)
157161

158162
def DEV(self, msg, *args, **kwargs):
@@ -174,7 +178,6 @@ def __init__(self, level):
174178
Initialize the logger with the name "root".
175179
"""
176180
super(RootLogger, self).__init__("root", level)
177-
self.log_json = False
178181

179182
def handle(self, record):
180183
if log_listeners:
@@ -189,6 +192,7 @@ class SManager(logging.Manager):
189192

190193
def __init__(self, rootnode):
191194
self.loggerClass = SLogger
195+
self.log_json = False
192196
super(SManager, self).__init__(rootnode)
193197

194198
def getLogger(self, name):
@@ -209,7 +213,6 @@ def getLogger(name=None):
209213

210214
if name:
211215
logger = SLogger.manager.getLogger(name)
212-
logger.log_json = rootLogger.log_json
213216
return logger
214217
else:
215218
return rootLogger
@@ -220,11 +223,11 @@ def configure(config_string=None, log_json=False, log_file=None):
220223
config_string = ":{}".format(DEFAULT_LOGLEVEL)
221224

222225
if log_json:
226+
SLogger.manager.log_json = True
223227
log_format = JSON_FORMAT
224-
rootLogger.log_json = True
225228
else:
229+
SLogger.manager.log_json = False
226230
log_format = PRINT_FORMAT
227-
rootLogger.log_json = False
228231

229232
if len(rootLogger.handlers) == 0:
230233
handler = StreamHandler()

ethereum/tests/test_logging.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,20 @@
55
from ethereum import slogging
66

77

8+
def setup_function(function):
9+
""" setup any state tied to the execution of the given function.
10+
Invoked for every test function in the module.
11+
"""
12+
function.snapshot = slogging.get_configuration()
13+
14+
15+
def teardown_function(function):
16+
""" teardown any state that was previously setup with a setup_function
17+
call.
18+
"""
19+
slogging.configure(**function.snapshot)
20+
21+
822
@pytest.mark.parametrize('level_name', ['critical', 'error', 'warning', 'info', 'debug', 'trace'])
923
def test_basic(caplog, level_name):
1024
slogging.configure(":trace")
@@ -35,7 +49,7 @@ def test_jsonconfig(caplog):
3549
slogging.configure(log_json=True)
3650
log = slogging.get_logger('prefix')
3751
log.warn('abc', a=1)
38-
assert json.loads(caplog.records()[0].msg) == dict(event='prefix.abc', a=1)
52+
assert json.loads(caplog.records()[0].msg) == dict(event='prefix.abc', a=1, level='WARNING')
3953

4054

4155
def test_configuration():
@@ -237,14 +251,14 @@ def test_bound_logger(caplog):
237251
with caplog.at_level(slogging.TRACE):
238252
bound_log_1.info("test1")
239253
assert "test1" in caplog.text
240-
assert "key1=value1" in caplog.text
254+
assert 'key1=value1' in caplog.text
241255

242256
bound_log_2 = bound_log_1.bind(key2="value2")
243257
with caplog.at_level(slogging.TRACE):
244258
bound_log_2.info("test2")
245259
assert "test2" in caplog.text
246-
assert "key1=value1" in caplog.text
247-
assert "key2=value2" in caplog.text
260+
assert 'key1=value1' in caplog.text
261+
assert 'key2=value2' in caplog.text
248262

249263

250264
def test_bound_logger_isolation(caplog):
@@ -260,18 +274,18 @@ def test_bound_logger_isolation(caplog):
260274
records = caplog.records()
261275
assert len(records) == 1
262276
assert "test1" in records[0].msg
263-
assert "key1=value1" in records[0].msg
277+
assert 'key1=value1' in records[0].msg
264278

265279
with caplog.at_level(slogging.TRACE):
266280
real_log.info("test2")
267281
records = caplog.records()
268282
assert len(records) == 2
269283
assert "test2" in records[1].msg
270-
assert "key1=value1" not in records[1].msg
284+
assert 'key1=value1' not in records[1].msg
271285

272286

273287
def test_highlight(caplog):
274-
slogging.configure()
288+
slogging.configure(log_json=False)
275289
log = slogging.getLogger()
276290

277291
log.DEV('testmessage')

ethereum/transactions.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ def log_dict(self):
157157
d = self.to_dict()
158158
d['sender'] = encode_hex(d['sender'] or '')
159159
d['to'] = encode_hex(d['to'])
160+
d['data'] = encode_hex(d['data'])
160161
return d
161162

162163
@property

0 commit comments

Comments
 (0)