Skip to content

Commit 9fdd5f8

Browse files
committed
Add styling to standard out for improved readability
Tune sleep / pauses down Set simln container restartPolicy: Never
1 parent 7831413 commit 9fdd5f8

File tree

6 files changed

+95
-66
lines changed

6 files changed

+95
-66
lines changed

resources/charts/bitcoincore/charts/cln/values.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,9 @@ tolerations: []
101101
affinity: {}
102102

103103
baseConfig: |
104-
log-level=debug
105-
# developer
106-
# dev-fast-gossip
104+
log-level=info
105+
developer
106+
dev-fast-gossip
107107
bitcoin-rpcuser=user
108108
# bitcoind.rpcpass are set in configmap.yaml
109109

resources/plugins/simln/charts/simln/values.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ image:
44
tag: "0.2.3"
55
pullPolicy: IfNotPresent
66

7+
restartPolicy: Never
8+
79
workingVolume:
810
name: working-volume
911
mountPath: /working

resources/plugins/simln/plugin.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,15 +200,17 @@ def transfer_cln_certs(name):
200200
def copyfile(pod_name, src_container, source_path, dst_name, dst_container, dst_path):
201201
namespace=get_default_namespace()
202202
file_data = read_file_from_container(pod_name, source_path, src_container, namespace)
203-
if not write_file_to_container(
203+
if write_file_to_container(
204204
dst_name,
205205
dst_container,
206206
dst_path,
207207
file_data,
208208
namespace=namespace,
209209
quiet=True,
210210
):
211-
print(f"Failed to copy {source_path} from {pod_name} to {dst_name}:{dst_path}")
211+
log.info(f"Copied {source_path} to {dst_path}")
212+
else:
213+
log.error(f"Failed to copy {source_path} from {pod_name} to {dst_name}:{dst_path}")
212214

213215

214216
def _sh(pod, method: str, params: tuple[str, ...]) -> str:

resources/scenarios/commander.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,27 @@ def auth_proxy_request(self, method, path, postdata):
8282
AuthServiceProxy.oldrequest = AuthServiceProxy._request
8383
AuthServiceProxy._request = auth_proxy_request
8484

85+
# Create a custom formatter
86+
class ColorFormatter(logging.Formatter):
87+
"""Custom formatter to add color based on log level."""
88+
# Define ANSI color codes
89+
RED = '\033[91m'
90+
YELLOW = '\033[93m'
91+
GREEN = '\033[92m'
92+
RESET = '\033[0m'
93+
94+
FORMATS = {
95+
logging.DEBUG: f"{RESET}%(name)-8s - Thread-%(thread)d - %(message)s{RESET}",
96+
logging.INFO: f"{RESET}%(name)-8s - %(message)s{RESET}",
97+
logging.WARNING: f"{YELLOW}%(name)-8s - %(message)s{RESET}",
98+
logging.ERROR: f"{RED}%(name)-8s - %(message)s{RESET}",
99+
logging.CRITICAL: f"{RED}##%(name)-8s - %(message)s##{RESET}"
100+
}
101+
102+
def format(self, record):
103+
log_fmt = self.FORMATS.get(record.levelno)
104+
formatter = logging.Formatter(log_fmt)
105+
return formatter.format(record)
85106

86107
class Commander(BitcoinTestFramework):
87108
# required by subclasses of BitcoinTestFramework
@@ -155,8 +176,7 @@ def setup(self):
155176
# Scenarios log directly to stdout which gets picked up by the
156177
# subprocess manager in the server, and reprinted to the global log.
157178
ch = logging.StreamHandler(sys.stdout)
158-
formatter = logging.Formatter(fmt="%(name)-8s %(message)s")
159-
ch.setFormatter(formatter)
179+
ch.setFormatter(ColorFormatter())
160180
self.log.addHandler(ch)
161181

162182
# Keep a separate index of tanks by pod name

resources/scenarios/ln_framework/ln.py

Lines changed: 47 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,28 @@ def to_lnd_chanpolicy(self, capacity):
103103
"min_htlc_msat_specified": True,
104104
}
105105

106+
# Create a custom formatter
107+
class ColorFormatter(logging.Formatter):
108+
"""Custom formatter to add color based on log level."""
109+
# Define ANSI color codes
110+
RED = '\033[91m'
111+
YELLOW = '\033[93m'
112+
GREEN = '\033[92m'
113+
RESET = '\033[0m'
114+
115+
FORMATS = {
116+
logging.DEBUG: f"{RESET}%(asctime)s - (name)-8s - Thread-%(thread)d - %(message)s{RESET}",
117+
logging.INFO: f"{RESET}%(asctime)s - (name)-8s - %(message)s{RESET}",
118+
logging.WARNING: f"{YELLOW}%(asctime)s - (name)-8s - %(message)s{RESET}",
119+
logging.ERROR: f"{RED}%(asctime)s - (name)-8s - %(message)s{RESET}",
120+
logging.CRITICAL: f"{RED}##%(asctime)s - (name)-8s - %(message)s##{RESET}"
121+
}
122+
123+
def format(self, record):
124+
log_fmt = self.FORMATS.get(record.levelno)
125+
formatter = logging.Formatter(log_fmt)
126+
return formatter.format(record)
127+
106128
class LNNode(ABC):
107129
@abstractmethod
108130
def __init__(self, pod_name):
@@ -111,8 +133,7 @@ def __init__(self, pod_name):
111133
# Configure logger if it has no handlers
112134
if not self.log.handlers:
113135
handler = logging.StreamHandler()
114-
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
115-
handler.setFormatter(formatter)
136+
handler.setFormatter(ColorFormatter())
116137
self.log.addHandler(handler)
117138
self.log.setLevel(logging.INFO)
118139

@@ -165,7 +186,7 @@ def rpc(self, method: str, params: list[str] = [], namespace: Optional[str] = "d
165186
continue
166187
return response
167188
except Exception as e:
168-
self.log.info(f"CLN rpc error: {e}")
189+
self.log.error(f"CLN rpc error: {e}, wait and retry...")
169190
sleep(2)
170191
return None
171192

@@ -181,7 +202,7 @@ def newaddress(self, max_tries=2):
181202
if "bech32" in res:
182203
return True, res["bech32"]
183204
else:
184-
self.log.info(
205+
self.log.warning(
185206
f"Couldn't get wallet address from {self.name}:\n {res}\n wait and retry..."
186207
)
187208
sleep(2)
@@ -207,23 +228,21 @@ def walletbalance(self, max_tries=2):
207228

208229
def connect(self, target_uri, max_tries=5):
209230
attempt=0
210-
self.log.info(f"CLN connect {self.name} to {target_uri}")
211231
while attempt < max_tries:
212232
attempt+=1
213233
response = self.rpc("connect", [target_uri])
214234
if response:
215235
res = json.loads(response)
216236
if "id" in res:
217-
self.log.debug(f"finished connect response: {response}")
218237
return {}
219238
elif "code" in res and res["code"] == 402:
220-
self.log.info(f"failed connect response: {response}")
239+
self.log.warning(f"failed connect 402: {response}, wait and retry...")
221240
sleep(5)
222241
else:
223242
return res
224243
else:
225-
self.log.debug(f"connect response: {response}")
226-
sleep(5)
244+
self.log.debug(f"connect response: {response}, wait and retry...")
245+
sleep(2)
227246
return ""
228247

229248
def channel(self, pk, capacity, push_amt, fee_rate, max_tries=5):
@@ -240,13 +259,13 @@ def channel(self, pk, capacity, push_amt, fee_rate, max_tries=5):
240259
if response:
241260
res = json.loads(response)
242261
if "txid" in res:
243-
self.log.debug(f"open channel succeeded: {res}")
244262
return {"txid": res["txid"], "outpoint": f'{res["txid"]}:{res["outnum"]}'}
245263
else:
246-
self.log.info(f"unable to open channel: {res}")
264+
self.log.warning(f"unable to open channel: {res}, wait and retry...")
265+
sleep(1)
247266
else:
248-
self.log.debug(f"channel response: {response}")
249-
sleep(5)
267+
self.log.debug(f"channel response: {response}, wait and retry...")
268+
sleep(2)
250269
return ""
251270

252271
def graph(self, max_tries=2):
@@ -257,34 +276,25 @@ def graph(self, max_tries=2):
257276
if response:
258277
res = json.loads(response)
259278
if "channels" in res:
260-
return {"edges": res["channels"]}
279+
# Map to desired output
280+
filtered_channels = [ch for ch in res['channels'] if ch['direction'] == 1]
281+
# Sort by short_channel_id - block -> index -> output
282+
sorted_channels = sorted(filtered_channels, key=lambda x: x['short_channel_id'])
283+
# Add capacity by dividing amount_msat by 1000
284+
for channel in sorted_channels:
285+
channel['capacity'] = channel['amount_msat'] // 1000
286+
return {'edges': sorted_channels}
261287
else:
262-
self.log.info(f"unable to open channel: {res}")
288+
self.log.warning(f"unable to open channel: {res}, wait and retry...")
289+
sleep(1)
263290
else:
264-
self.log.debug(f"channel response: {response}")
265-
sleep(5)
291+
self.log.debug(f"channel response: {response}, wait and retry...")
292+
sleep(2)
266293
return ""
267294

268295
def update(self, txid_hex: str, policy: dict, capacity: int, max_tries=2):
269-
self.log.info("Channel Policy Updates not supported by CLN yet!")
296+
self.log.warning("Channel Policy Updates not supported by CLN yet!")
270297
return
271-
# ln_policy = Policy.from_dict(policy).to_lnd_chanpolicy(capacity)
272-
# data = {"chan_point": {"funding_txid_str": txid_hex, "output_index": 0}, **ln_policy}
273-
# attempt=0
274-
# while attempt < max_tries:
275-
# attempt+=1
276-
# response = self.rpc("setchannel")
277-
# if response:
278-
# res = json.loads(response)
279-
# if "channels" in res:
280-
# print(f"graph succeeded: {res}")
281-
# return {"edges": res["channels"]}
282-
# else:
283-
# print(f"unable to open channel: {res}")
284-
# else:
285-
# print(f"channel response: {response}")
286-
# sleep(5)
287-
# return ""
288298

289299
class LND(LNNode):
290300
def __init__(self, pod_name):
@@ -350,7 +360,7 @@ def newaddress(self, max_tries=10):
350360
if "address" in res:
351361
return True, res["address"]
352362
else:
353-
self.log.info(
363+
self.log.warning(
354364
f"Couldn't get wallet address from {self.name}:\n {res}\n wait and retry..."
355365
)
356366
sleep(1)
@@ -388,9 +398,8 @@ def channel(self, pk, capacity, push_amt, fee_rate):
388398
if "result" in res:
389399
res["txid"] = self.b64_to_hex(res["result"]["chan_pending"]["txid"], reverse=True)
390400
res["outpoint"] = f'{res["txid"]}:{res["result"]["chan_pending"]["output_index"]}'
391-
self.log.info(f"LND channel RESPONSE: {res}")
392401
except Exception as e:
393-
self.log.info(f"Error opening LND channel: {e}")
402+
self.log.error(f"Error opening LND channel: {e}")
394403
return res
395404

396405
def update(self, txid_hex: str, policy: dict, capacity: int):

resources/scenarios/ln_init.py

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from commander import Commander
77
from ln_framework.ln import Policy
88

9-
THREAD_JOIN_TIMEOUT=15
9+
THREAD_JOIN_TIMEOUT=20
1010

1111
class LNInit(Commander):
1212
def set_test_params(self):
@@ -145,7 +145,7 @@ def get_ln_uri(self, ln):
145145
for ch in self.channels:
146146
node_names = self.node_names(ln_nodes)
147147
if not ch["source"] in node_names or not ch["target"] in node_names:
148-
self.log.info(f"LN Channel {ch} not available, removing")
148+
self.log.error(f"LN Channel {ch} not available, removing")
149149
self.channels.remove(ch)
150150
continue
151151
src = self.lns[ch["source"]]
@@ -184,7 +184,7 @@ def connect_ln(self, pair):
184184
threading.Thread(target=connect_ln, args=(self, pair)) for pair in connections
185185
]
186186
for thread in p2p_threads:
187-
sleep(5)
187+
sleep(1)
188188
thread.start()
189189

190190
all(thread.join(timeout=THREAD_JOIN_TIMEOUT) is None for thread in p2p_threads)
@@ -258,7 +258,7 @@ def open_channel(self, ch, fee_rate):
258258
assert index == ch["id"]["index"], "Channel ID indexes are not consecutive"
259259
assert fee_rate >= 1, "Too many TXs in block, out of fee range"
260260
t = threading.Thread(target=open_channel, args=(self, ch, fee_rate))
261-
sleep(5)
261+
sleep(2)
262262
t.start()
263263
ch_threads.append(t)
264264

@@ -275,13 +275,9 @@ def open_channel(self, ch, fee_rate):
275275
block_txs = block["tx"]
276276
block_height = block["height"]
277277
for ch in channels:
278-
if "txid" not in ch:
279-
print(f"{ch} does not have a txid")
280-
continue
281-
assert ch["id"]["block"] == block_height, f"Actual block:{block_height}\n{ch}"
282-
assert (
283-
block_txs[ch["id"]["index"]] == ch["txid"]
284-
), f"Actual txid:{block_txs[ch["id"]["index"]]}\n{ch}"
278+
assert ch["txid"] != "N/A", f"Channel:{ch} did not receive txid"
279+
assert ch["id"]["block"] == block_height, f"Actual block:{block_height}"
280+
assert ch["txid"] in block_txs, f"Block:{block_height} does not contain {ch["txid"]}"
285281
self.log.info("👍")
286282

287283
gen(5)
@@ -299,10 +295,10 @@ def ln_all_chs(self, ln):
299295
self.log.info(f"LN {ln.name} has graph with all {expected} channels")
300296

301297
ch_ann_threads = [
302-
threading.Thread(target=ln_all_chs, args=(self, ln)) for ln in self.lns.values()
298+
threading.Thread(target=ln_all_chs, args=(self, ln)) for ln in ln_nodes
303299
]
304300
for thread in ch_ann_threads:
305-
sleep(5)
301+
sleep(1)
306302
thread.start()
307303

308304
all(thread.join(timeout=THREAD_JOIN_TIMEOUT) is None for thread in ch_ann_threads)
@@ -359,16 +355,18 @@ def policy_equal(pol1, pol2, capacity):
359355
return pol1.to_lnd_chanpolicy(capacity) == pol2.to_lnd_chanpolicy(capacity)
360356

361357
def matching_graph(self, expected, ln):
362-
while True:
358+
done = False
359+
while not done:
363360
actual = ln.graph()["edges"]
364-
assert len(expected) == len(actual)
365-
done = True
361+
self.log.debug(f"LN {ln.name} channel graph edges: {actual}")
362+
assert (len(expected) == len(actual),f"Expected edges {expected}, actual edges {actual}")
363+
if len(actual) > 0: done = True
366364
for i, actual_ch in enumerate(actual):
367365
expected_ch = expected[i]
368366
capacity = expected_ch["capacity"]
369367
# We assert this because it isn't updated as part of policy.
370368
# If this fails we have a bigger issue
371-
assert int(actual_ch["capacity"]) == capacity
369+
assert int(actual_ch["capacity"]) == capacity, f"LN {ln.name} graph capacity mismatch:\n actual: {actual_ch}\n expected: {expected_ch}"
372370

373371
# Policies were not defined in network.yaml
374372
if "source_policy" not in expected_ch or "target_policy" not in expected_ch:
@@ -389,17 +387,15 @@ def matching_graph(self, expected, ln):
389387
):
390388
continue
391389
done = False
392-
break
393390
if done:
394391
self.log.info(f"LN {ln.name} graph channel policies all match expected source")
395-
break
396392
else:
397-
sleep(1)
393+
sleep(5)
398394

399395
expected = sorted(self.channels, key=lambda ch: (ch["id"]["block"], ch["id"]["index"]))
400396
policy_threads = [
401397
threading.Thread(target=matching_graph, args=(self, expected, ln))
402-
for ln in self.lns.values()
398+
for ln in ln_nodes
403399
]
404400
for thread in policy_threads:
405401
thread.start()

0 commit comments

Comments
 (0)