# Supports tracking channels with a non-bitcoin chain hashes. Currently enables all kinds of fun DoS attacks.
non_bitcoin_chain_hash_routing = []
fuzztarget = ["secp256k1/fuzztarget", "bitcoin/fuzztarget"]
+# Unlog messages superior at targeted level.
+max_level_off = []
+max_level_error = []
+max_level_warn = []
+max_level_info = []
+max_level_debug = []
[dependencies]
bitcoin = "0.13"
use lightning::chain::chaininterface::{FeeEstimator, ConfirmationTarget};
use lightning::chain::transaction::OutPoint;
use lightning::util::reset_rng_state;
+use lightning::util::logger::Logger;
+
+mod utils;
+
+use utils::test_logger;
use secp256k1::key::{PublicKey, SecretKey};
use secp256k1::Secp256k1;
use std::sync::atomic::{AtomicUsize,Ordering};
+use std::sync::Arc;
#[inline]
pub fn slice_to_be16(v: &[u8]) -> u16 {
input: &input,
};
+ let logger: Arc<Logger> = Arc::new(test_logger::TestLogger::new());
+
macro_rules! get_slice {
($len: expr) => {
match input.get_slice($len as usize) {
let mut channel = if get_slice!(1)[0] != 0 {
let chan_value = slice_to_be24(get_slice!(3));
- let mut chan = Channel::new_outbound(&fee_est, chan_keys!(), their_pubkey, chan_value, get_slice!(1)[0] == 0, slice_to_be64(get_slice!(8)));
+ let mut chan = Channel::new_outbound(&fee_est, chan_keys!(), their_pubkey, chan_value, get_slice!(1)[0] == 0, slice_to_be64(get_slice!(8)), Arc::clone(&logger));
chan.get_open_channel(Sha256dHash::from(get_slice!(32)), &fee_est).unwrap();
let accept_chan = if get_slice!(1)[0] == 0 {
decode_msg_with_len16!(msgs::AcceptChannel, 270, 1)
} else {
decode_msg!(msgs::OpenChannel, 2*32+6*8+4+2*2+6*33+1)
};
- let mut chan = match Channel::new_from_req(&fee_est, chan_keys!(), their_pubkey, &open_chan, slice_to_be64(get_slice!(8)), false, get_slice!(1)[0] == 0) {
+ let mut chan = match Channel::new_from_req(&fee_est, chan_keys!(), their_pubkey, &open_chan, slice_to_be64(get_slice!(8)), false, get_slice!(1)[0] == 0, Arc::clone(&logger)) {
Ok(chan) => chan,
Err(_) => return,
};
use lightning::ln::router::Router;
use lightning::util::events::{EventsProvider,Event};
use lightning::util::reset_rng_state;
+use lightning::util::logger::Logger;
+
+mod utils;
+
+use utils::test_logger;
use secp256k1::key::{PublicKey,SecretKey};
use secp256k1::Secp256k1;
Err(_) => return,
};
+ let logger: Arc<Logger> = Arc::new(test_logger::TestLogger::new());
let monitor = Arc::new(TestChannelMonitor{});
- let watch = Arc::new(ChainWatchInterfaceUtil::new());
+ let watch = Arc::new(ChainWatchInterfaceUtil::new(Arc::clone(&logger)));
let broadcast = Arc::new(TestBroadcaster{});
- let channelmanager = ChannelManager::new(our_network_key, slice_to_be32(get_slice!(4)), get_slice!(1)[0] != 0, Network::Bitcoin, fee_est.clone(), monitor.clone(), watch.clone(), broadcast.clone()).unwrap();
- let router = Arc::new(Router::new(PublicKey::from_secret_key(&secp_ctx, &our_network_key).unwrap()));
+ let channelmanager = ChannelManager::new(our_network_key, slice_to_be32(get_slice!(4)), get_slice!(1)[0] != 0, Network::Bitcoin, fee_est.clone(), monitor.clone(), watch.clone(), broadcast.clone(), Arc::clone(&logger)).unwrap();
+ let router = Arc::new(Router::new(PublicKey::from_secret_key(&secp_ctx, &our_network_key).unwrap(), Arc::clone(&logger)));
let peers = RefCell::new([false; 256]);
let handler = PeerManager::new(MessageHandler {
chan_handler: channelmanager.clone(),
route_handler: router.clone(),
- }, our_network_key);
+ }, our_network_key, Arc::clone(&logger));
let mut should_forward = false;
let mut payments_received = Vec::new();
use lightning::ln::msgs::{MsgDecodable, RoutingMessageHandler};
use lightning::ln::router::{Router, RouteHint};
use lightning::util::reset_rng_state;
+use lightning::util::logger::Logger;
use secp256k1::key::PublicKey;
use secp256k1::Secp256k1;
+mod utils;
+
+use utils::test_logger;
+
+use std::sync::Arc;
+
#[inline]
pub fn slice_to_be16(v: &[u8]) -> u16 {
((v[0] as u16) << 8*1) |
}
}
+ let logger: Arc<Logger> = Arc::new(test_logger::TestLogger::new());
+
let our_pubkey = get_pubkey!();
- let router = Router::new(our_pubkey.clone());
+ let router = Router::new(our_pubkey.clone(), Arc::clone(&logger));
loop {
match get_slice!(1)[0] {
--- /dev/null
+pub(crate) mod test_logger;
--- /dev/null
+use lightning::util::logger::{Logger, Level, Record};
+
+pub struct TestLogger {
+ level: Level,
+}
+
+impl TestLogger {
+ pub fn new() -> TestLogger {
+ TestLogger {
+ level: Level::Off,
+ }
+ }
+ pub fn enable(&mut self, level: Level) {
+ self.level = level;
+ }
+}
+
+impl Logger for TestLogger {
+ fn log(&self, record: &Record) {
+ #[cfg(any(test, not(feature = "fuzztarget")))]
+ println!("{:<5} [{} : {}, {}] {}", record.level.to_string(), record.module_path, record.file, record.line, record.args);
+ }
+}
use bitcoin::blockdata::transaction::Transaction;
use bitcoin::blockdata::script::Script;
use bitcoin::util::hash::Sha256dHash;
-use std::sync::{Mutex,Weak,MutexGuard};
+use util::logger::Logger;
+use std::sync::{Mutex,Weak,MutexGuard,Arc};
use std::sync::atomic::{AtomicUsize, Ordering};
/// An interface to request notification of certain scripts as they appear the
pub struct ChainWatchInterfaceUtil {
watched: Mutex<(Vec<Script>, Vec<(Sha256dHash, u32)>, bool)>, //TODO: Something clever to optimize this
listeners: Mutex<Vec<Weak<ChainListener>>>,
- reentered: AtomicUsize
+ reentered: AtomicUsize,
+ logger: Arc<Logger>,
}
/// Register listener
}
impl ChainWatchInterfaceUtil {
- pub fn new() -> ChainWatchInterfaceUtil {
+ pub fn new(logger: Arc<Logger>) -> ChainWatchInterfaceUtil {
ChainWatchInterfaceUtil {
watched: Mutex::new((Vec::new(), Vec::new(), false)),
listeners: Mutex::new(Vec::new()),
- reentered: AtomicUsize::new(1)
+ reentered: AtomicUsize::new(1),
+ logger: logger,
}
}
extern crate secp256k1;
#[cfg(test)] extern crate hex;
+#[macro_use]
+pub mod util;
pub mod chain;
pub mod ln;
-pub mod util;
use chain::transaction::OutPoint;
use util::{transaction_utils,rng};
use util::sha2::Sha256;
+use util::logger::{Logger, Record};
use std;
use std::default::Default;
use std::{cmp,mem};
use std::time::Instant;
+use std::sync::{Arc};
pub struct ChannelKeys {
pub funding_key: SecretKey,
their_shutdown_scriptpubkey: Option<Script>,
channel_monitor: ChannelMonitor,
+
+ logger: Arc<Logger>,
}
const OUR_MAX_HTLCS: u16 = 5; //TODO
// Constructors:
/// panics if channel_value_satoshis is >= `MAX_FUNDING_SATOSHIS`
- pub fn new_outbound(fee_estimator: &FeeEstimator, chan_keys: ChannelKeys, their_node_id: PublicKey, channel_value_satoshis: u64, announce_publicly: bool, user_id: u64) -> Channel {
+ pub fn new_outbound(fee_estimator: &FeeEstimator, chan_keys: ChannelKeys, their_node_id: PublicKey, channel_value_satoshis: u64, announce_publicly: bool, user_id: u64, logger: Arc<Logger>) -> Channel {
if channel_value_satoshis >= MAX_FUNDING_SATOSHIS {
panic!("funding value > 2^24");
}
their_shutdown_scriptpubkey: None,
channel_monitor: channel_monitor,
+
+ logger,
}
}
/// Assumes chain_hash has already been checked and corresponds with what we expect!
/// Generally prefers to take the DisconnectPeer action on failure, as a notice to the sender
/// that we're rejecting the new channel.
- pub fn new_from_req(fee_estimator: &FeeEstimator, chan_keys: ChannelKeys, their_node_id: PublicKey, msg: &msgs::OpenChannel, user_id: u64, require_announce: bool, allow_announce: bool) -> Result<Channel, HandleError> {
+ pub fn new_from_req(fee_estimator: &FeeEstimator, chan_keys: ChannelKeys, their_node_id: PublicKey, msg: &msgs::OpenChannel, user_id: u64, require_announce: bool, allow_announce: bool, logger: Arc<Logger>) -> Result<Channel, HandleError> {
// Check sanity of message fields:
if msg.funding_satoshis >= MAX_FUNDING_SATOSHIS {
return Err(HandleError{err: "funding value > 2^24", action: Some(msgs::ErrorAction::DisconnectPeer{ msg: None })});
their_shutdown_scriptpubkey: None,
channel_monitor: channel_monitor,
+
+ logger,
};
let obscure_factor = chan.get_commitment_transaction_number_obscure_factor();
match self.secp_ctx.verify(&sighash, &msg.signature, &self.their_funding_pubkey) {
Ok(_) => {},
- Err(_) => {
+ Err(_e) => {
// The remote end may have decided to revoke their output due to inconsistent dust
// limits, so check for that case by re-checking the signature here.
closing_tx = self.build_closing_transaction(msg.fee_satoshis, true).0;
let (our_signature, commitment_tx) = match self.get_outbound_funding_created_signature() {
Ok(res) => res,
Err(e) => {
+ log_error!(self, "Got bad signatures: {}!", e.err);
self.channel_monitor.unset_funding_info();
return Err(e);
}
use ln::chan_utils;
use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
use chain::transaction::OutPoint;
+ use util::test_utils;
+ use util::logger::Logger;
use secp256k1::{Secp256k1,Message,Signature};
use secp256k1::key::{SecretKey,PublicKey};
use crypto::sha2::Sha256;
use crypto::digest::Digest;
+ use std::sync::Arc;
struct TestFeeEstimator {
fee_est: u64
fn outbound_commitment_test() {
// Test vectors from BOLT 3 Appendix C:
let feeest = TestFeeEstimator{fee_est: 15000};
+ let logger : Arc<Logger> = Arc::new(test_utils::TestLogger::new());
let secp_ctx = Secp256k1::new();
let chan_keys = ChannelKeys {
assert_eq!(PublicKey::from_secret_key(&secp_ctx, &chan_keys.funding_key).unwrap().serialize()[..],
hex::decode("023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb").unwrap()[..]);
- let mut chan = Channel::new_outbound(&feeest, chan_keys, PublicKey::new(), 10000000, false, 42); // Nothing uses their network key in this test
+ let mut chan = Channel::new_outbound(&feeest, chan_keys, PublicKey::new(), 10000000, false, 42, Arc::clone(&logger)); // Nothing uses their network key in this test
chan.their_to_self_delay = 144;
chan.our_dust_limit_satoshis = 546;
use util::{byte_utils, events, internal_traits, rng};
use util::sha2::Sha256;
use util::chacha20poly1305rfc::ChaCha20;
+use util::logger::{Logger, Record};
use crypto;
use crypto::mac::{Mac,MacResult};
our_network_key: SecretKey,
pending_events: Mutex<Vec<events::Event>>,
+
+ logger: Arc<Logger>,
}
const CLTV_EXPIRY_DELTA: u16 = 6 * 24 * 2; //TODO?
/// fee_proportional_millionths is an optional fee to charge any payments routed through us.
/// Non-proportional fees are fixed according to our risk using the provided fee estimator.
/// panics if channel_value_satoshis is >= `MAX_FUNDING_SATOSHIS`!
- pub fn new(our_network_key: SecretKey, fee_proportional_millionths: u32, announce_channels_publicly: bool, network: Network, feeest: Arc<FeeEstimator>, monitor: Arc<ManyChannelMonitor>, chain_monitor: Arc<ChainWatchInterface>, tx_broadcaster: Arc<BroadcasterInterface>) -> Result<Arc<ChannelManager>, secp256k1::Error> {
+ pub fn new(our_network_key: SecretKey, fee_proportional_millionths: u32, announce_channels_publicly: bool, network: Network, feeest: Arc<FeeEstimator>, monitor: Arc<ManyChannelMonitor>, chain_monitor: Arc<ChainWatchInterface>, tx_broadcaster: Arc<BroadcasterInterface>, logger: Arc<Logger>) -> Result<Arc<ChannelManager>, secp256k1::Error> {
let secp_ctx = Secp256k1::new();
let res = Arc::new(ChannelManager {
our_network_key,
pending_events: Mutex::new(Vec::new()),
+
+ logger,
});
let weak_res = Arc::downgrade(&res);
res.chain_monitor.register_listener(weak_res);
}
};
- let channel = Channel::new_outbound(&*self.fee_estimator, chan_keys, their_network_key, channel_value_satoshis, self.announce_channels_publicly, user_id);
+ let channel = Channel::new_outbound(&*self.fee_estimator, chan_keys, their_network_key, channel_value_satoshis, self.announce_channels_publicly, user_id, Arc::clone(&self.logger));
let res = channel.get_open_channel(self.genesis_hash.clone(), &*self.fee_estimator)?;
let mut channel_state = self.channel_state.lock().unwrap();
match channel_state.by_id.insert(channel.channel_id(), channel) {
/// Call this upon creation of a funding transaction for the given channel.
/// Panics if a funding transaction has already been provided for this channel.
pub fn funding_transaction_generated(&self, temporary_channel_id: &[u8; 32], funding_txo: OutPoint) {
+
macro_rules! add_pending_event {
($event: expr) => {
{
(chan, funding_msg.0, funding_msg.1)
},
Err(e) => {
+ log_error!(self, "Got bad signatures: {}!", e.err);
mem::drop(channel_state);
add_pending_event!(events::Event::HandleError {
node_id: chan.get_their_node_id(),
if !add_htlc_msgs.is_empty() {
let (commitment_msg, monitor) = match forward_chan.send_commitment() {
Ok(res) => res,
- Err(_) => {
+ Err(_e) => {
//TODO: Handle...this is bad!
continue;
},
if let Ok(Some(funding_locked)) = chan_res {
let announcement_sigs = match self.get_announcement_sigs(channel) {
Ok(res) => res,
- Err(_e) => {
+ Err(e) => {
+ log_error!(self, "Got error handling message: {}!", e.err);
//TODO: push e on events and blow up the channel (it has bad keys)
return true;
}
}
};
- let channel = Channel::new_from_req(&*self.fee_estimator, chan_keys, their_node_id.clone(), msg, 0, false, self.announce_channels_publicly)?;
+ let channel = Channel::new_from_req(&*self.fee_estimator, chan_keys, their_node_id.clone(), msg, 0, false, self.announce_channels_publicly, Arc::clone(&self.logger))?;
let accept_msg = channel.get_accept_channel()?;
channel_state.by_id.insert(channel.channel_id(), channel);
Ok(accept_msg)
use ln::msgs::{MsgEncodable,ChannelMessageHandler,RoutingMessageHandler};
use util::test_utils;
use util::events::{Event, EventsProvider};
+ use util::logger::Logger;
use bitcoin::util::hash::Sha256dHash;
use bitcoin::blockdata::block::{Block, BlockHeader};
let mut nodes = Vec::new();
let mut rng = thread_rng();
let secp_ctx = Secp256k1::new();
+ let logger: Arc<Logger> = Arc::new(test_utils::TestLogger::new());
for _ in 0..node_count {
let feeest = Arc::new(test_utils::TestFeeEstimator { sat_per_kw: 253 });
- let chain_monitor = Arc::new(chaininterface::ChainWatchInterfaceUtil::new());
+ let chain_monitor = Arc::new(chaininterface::ChainWatchInterfaceUtil::new(Arc::clone(&logger)));
let tx_broadcaster = Arc::new(test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new())});
let chan_monitor = Arc::new(test_utils::TestChannelMonitor::new(chain_monitor.clone(), tx_broadcaster.clone()));
let node_id = {
rng.fill_bytes(&mut key_slice);
SecretKey::from_slice(&secp_ctx, &key_slice).unwrap()
};
- let node = ChannelManager::new(node_id.clone(), 0, true, Network::Testnet, feeest.clone(), chan_monitor.clone(), chain_monitor.clone(), tx_broadcaster.clone()).unwrap();
- let router = Router::new(PublicKey::from_secret_key(&secp_ctx, &node_id).unwrap());
+ let node = ChannelManager::new(node_id.clone(), 0, true, Network::Testnet, feeest.clone(), chan_monitor.clone(), chain_monitor.clone(), tx_broadcaster.clone(), Arc::clone(&logger)).unwrap();
+ let router = Router::new(PublicKey::from_secret_key(&secp_ctx, &node_id).unwrap(), Arc::clone(&logger));
nodes.push(Node { feeest, chain_monitor, tx_broadcaster, chan_monitor, node_id, node, router });
}
use ln::peer_channel_encryptor::{PeerChannelEncryptor,NextNoiseStep};
use util::byte_utils;
use util::events::{EventsProvider,Event};
+use util::logger::{Logger, Record};
use std::collections::{HashMap,LinkedList};
use std::sync::{Arc, Mutex};
pending_events: Mutex<Vec<Event>>,
our_node_secret: SecretKey,
initial_syncs_sent: AtomicUsize,
+ logger: Arc<Logger>,
}
/// Manages and reacts to connection events. You probably want to use file descriptors as PeerIds.
/// PeerIds may repeat, but only after disconnect_event() has been called.
impl<Descriptor: SocketDescriptor> PeerManager<Descriptor> {
- pub fn new(message_handler: MessageHandler, our_node_secret: SecretKey) -> PeerManager<Descriptor> {
+ pub fn new(message_handler: MessageHandler, our_node_secret: SecretKey, logger: Arc<Logger>) -> PeerManager<Descriptor> {
PeerManager {
message_handler: message_handler,
peers: Mutex::new(PeerHolder { peers: HashMap::new(), node_id_to_descriptor: HashMap::new() }),
pending_events: Mutex::new(Vec::new()),
our_node_secret: our_node_secret,
initial_syncs_sent: AtomicUsize::new(0),
+ logger,
}
}
match $thing {
Ok(x) => x,
Err(e) => {
- println!("Got error handling message: {}!", e.err);
if let Some(action) = e.action {
match action {
msgs::ErrorAction::UpdateFailHTLC { msg } => {
match $thing {
Ok(x) => x,
Err(_e) => {
- println!("Error decoding message");
//TODO: Handle e?
return Err(PeerHandleError{ no_connection_possible: false });
}
match $thing {
Ok(x) => x,
Err(_e) => {
- println!("Error decoding message, ignoring due to lnd spec incompatibility. See https://github.com/lightningnetwork/lnd/issues/1407");
+ log_debug!(self, "Error decoding message, ignoring due to lnd spec incompatibility. See https://github.com/lightningnetwork/lnd/issues/1407");
continue;
}
};
use ln::msgs;
use util::events;
use util::test_utils;
+ use util::logger::Logger;
use secp256k1::Secp256k1;
use secp256k1::key::{SecretKey, PublicKey};
let secp_ctx = Secp256k1::new();
let mut peers = Vec::new();
let mut rng = thread_rng();
+ let logger : Arc<Logger> = Arc::new(test_utils::TestLogger::new());
for _ in 0..peer_count {
let chan_handler = test_utils::TestChannelMessageHandler::new();
SecretKey::from_slice(&secp_ctx, &key_slice).unwrap()
};
let msg_handler = MessageHandler { chan_handler: Arc::new(chan_handler), route_handler: Arc::new(router) };
- let peer = PeerManager::new(msg_handler, node_id);
+ let peer = PeerManager::new(msg_handler, node_id, Arc::clone(&logger));
peers.push(peer);
}
use ln::channelmanager;
use ln::msgs::{ErrorAction,HandleError,RoutingMessageHandler,MsgEncodable,NetAddress,GlobalFeatures};
use ln::msgs;
+use util::logger::Logger;
use std::cmp;
-use std::sync::RwLock;
+use std::sync::{RwLock,Arc};
use std::collections::{HashMap,BinaryHeap};
use std::collections::hash_map::Entry;
pub struct Router {
secp_ctx: Secp256k1,
network_map: RwLock<NetworkMap>,
+ logger: Arc<Logger>,
}
macro_rules! secp_verify_sig {
}
impl Router {
- pub fn new(our_pubkey: PublicKey) -> Router {
+ pub fn new(our_pubkey: PublicKey, logger: Arc<Logger>) -> Router {
let mut nodes = HashMap::new();
nodes.insert(our_pubkey.clone(), NodeInfo {
channels: Vec::new(),
our_node_id: our_pubkey,
nodes: nodes,
}),
+ logger,
}
}
use ln::channelmanager;
use ln::router::{Router,NodeInfo,NetworkMap,ChannelInfo,DirectionalChannelInfo,RouteHint};
use ln::msgs::GlobalFeatures;
+ use util::test_utils;
+ use util::logger::Logger;
use bitcoin::util::hash::Sha256dHash;
use secp256k1::key::{PublicKey,SecretKey};
use secp256k1::Secp256k1;
+ use std::sync::Arc;
+
#[test]
fn route_test() {
let secp_ctx = Secp256k1::new();
let our_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap()[..]).unwrap()).unwrap();
- let router = Router::new(our_id);
+ let logger: Arc<Logger> = Arc::new(test_utils::TestLogger::new());
+ let router = Router::new(our_id, Arc::clone(&logger));
// Build network from our_id to node8:
//
--- /dev/null
+// Pruned copy of crate rust log, without global logger
+// https://github.com/rust-lang-nursery/log #7a60286
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/// There is currently 2 ways to filter log messages. First one, by using compilation flag, e.g "max_level_off".
+/// The second one, client-side by implementing check against Record Level field, e.g TestLogger in test_utils.
+/// Each module may have its own Logger or share one.
+
+use std::cmp;
+use std::fmt;
+
+static LOG_LEVEL_NAMES: [&'static str; 6] = ["OFF", "ERROR", "WARN", "INFO", "DEBUG", "TRACE"];
+
+/// An enum representing the available verbosity levels of the logger.
+#[derive(Copy, Clone, Eq, Debug, Hash)]
+pub enum Level {
+ ///Designates logger being silent
+ Off,
+ /// Designates very serious errors
+ Error,
+ /// Designates hazardous situations
+ Warn,
+ /// Designates useful information
+ Info,
+ /// Designates lower priority information
+ Debug,
+ /// Designates very low priority, often extremely verbose, information
+ Trace,
+}
+
+impl PartialEq for Level {
+ #[inline]
+ fn eq(&self, other: &Level) -> bool {
+ *self as usize == *other as usize
+ }
+}
+
+impl PartialOrd for Level {
+ #[inline]
+ fn partial_cmp(&self, other: &Level) -> Option<cmp::Ordering> {
+ Some(self.cmp(other))
+ }
+
+ #[inline]
+ fn lt(&self, other: &Level) -> bool {
+ (*self as usize) < *other as usize
+ }
+
+ #[inline]
+ fn le(&self, other: &Level) -> bool {
+ *self as usize <= *other as usize
+ }
+
+ #[inline]
+ fn gt(&self, other: &Level) -> bool {
+ *self as usize > *other as usize
+ }
+
+ #[inline]
+ fn ge(&self, other: &Level) -> bool {
+ *self as usize >= *other as usize
+ }
+}
+
+impl Ord for Level {
+ #[inline]
+ fn cmp(&self, other: &Level) -> cmp::Ordering {
+ (*self as usize).cmp(&(*other as usize))
+ }
+}
+
+impl fmt::Display for Level {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.pad(LOG_LEVEL_NAMES[*self as usize])
+ }
+}
+
+impl Level {
+ /// Returns the most verbose logging level.
+ #[inline]
+ pub fn max() -> Level {
+ Level::Trace
+ }
+}
+
+/// A Record, unit of logging output with Metadata to enable filtering
+/// Module_path, file, line to inform on log's source
+#[derive(Clone,Debug)]
+pub struct Record<'a> {
+ /// The verbosity level of the message.
+ pub level: Level,
+ /// The message body.
+ pub args: fmt::Arguments<'a>,
+ /// The module path of the message.
+ pub module_path: &'a str,
+ /// The source file containing the message.
+ pub file: &'a str,
+ /// The line containing the message.
+ pub line: u32,
+}
+
+impl<'a> Record<'a> {
+ /// Returns a new Record.
+ #[inline]
+ pub fn new(level: Level, args: fmt::Arguments<'a>, module_path: &'a str, file: &'a str, line: u32) -> Record<'a> {
+ Record {
+ level,
+ args,
+ module_path,
+ file,
+ line
+ }
+ }
+}
+
+/// A trait encapsulating the operations required of a logger
+pub trait Logger: Sync + Send {
+ /// Logs the `Record`
+ fn log(&self, record: &Record);
+}
+
+#[cfg(test)]
+mod tests {
+ use util::logger::{Logger, Level, Record};
+ use util::test_utils::TestLogger;
+ use std::sync::{Arc};
+
+ #[test]
+ fn test_level_show() {
+ assert_eq!("INFO", Level::Info.to_string());
+ assert_eq!("ERROR", Level::Error.to_string());
+ assert_ne!("WARN", Level::Error.to_string());
+ }
+
+ struct WrapperLog {
+ logger: Arc<Logger>
+ }
+
+ impl WrapperLog {
+ fn new(logger: Arc<Logger>) -> WrapperLog {
+ WrapperLog {
+ logger,
+ }
+ }
+
+ fn call_macros(&self) {
+ log_error!(self, "This is an error");
+ log_warn!(self, "This is a warning");
+ log_info!(self, "This is an info");
+ log_debug!(self, "This is a debug");
+ log_trace!(self, "This is a trace");
+ }
+ }
+
+ #[test]
+ fn test_logging_macros() {
+ let mut logger = TestLogger::new();
+ logger.enable(Level::Trace);
+ let logger : Arc<Logger> = Arc::new(logger);
+ let wrapper = WrapperLog::new(Arc::clone(&logger));
+ wrapper.call_macros();
+ }
+}
--- /dev/null
+use util::logger::Record;
+
+macro_rules! log_internal {
+ ($self: ident, $lvl:expr, $($arg:tt)+) => (
+ &$self.logger.log(&Record::new($lvl, format_args!($($arg)+), module_path!(), file!(), line!()));
+ );
+}
+
+macro_rules! log_error {
+ ($self: ident, $($arg:tt)*) => (
+ #[cfg(not(any(feature = "max_level_off")))]
+ log_internal!($self, $crate::util::logger::Level::Error, $($arg)*);
+ )
+}
+
+macro_rules! log_warn {
+ ($self: ident, $($arg:tt)*) => (
+ #[cfg(not(any(feature = "max_level_off", feature = "max_level_error")))]
+ log_internal!($self, $crate::util::logger::Level::Warn, $($arg)*);
+ )
+}
+
+macro_rules! log_info {
+ ($self: ident, $($arg:tt)*) => (
+ #[cfg(not(any(feature = "max_level_off", feature = "max_level_error", feature = "max_level_warn")))]
+ log_internal!($self, $crate::util::logger::Level::Info, $($arg)*);
+ )
+}
+
+macro_rules! log_debug {
+ ($self: ident, $($arg:tt)*) => (
+ #[cfg(not(any(feature = "max_level_off", feature = "max_level_error", feature = "max_level_warn", feature = "max_level_info")))]
+ log_internal!($self, $crate::util::logger::Level::Debug, $($arg)*);
+ )
+}
+
+macro_rules! log_trace {
+ ($self: ident, $($arg:tt)*) => (
+ #[cfg(not(any(feature = "max_level_off", feature = "max_level_error", feature = "max_level_warn", feature = "max_level_info", feature = "max_level_debug")))]
+ log_internal!($self, $crate::util::logger::Level::Trace, $($arg)*);
+ )
+}
#[cfg(test)]
pub(crate) mod test_utils;
+
+#[macro_use]
+pub(crate) mod macro_logger;
+
+pub mod logger;
use ln::msgs;
use ln::msgs::{HandleError};
use util::events;
+use util::logger::{Logger, Level, Record};
use bitcoin::blockdata::transaction::Transaction;
}
fn handle_htlc_fail_channel_update(&self, _update: &msgs::HTLCFailChannelUpdate) {}
}
+
+pub struct TestLogger {
+ level: Level,
+}
+
+impl TestLogger {
+ pub fn new() -> TestLogger {
+ TestLogger {
+ level: Level::Off,
+ }
+ }
+ pub fn enable(&mut self, level: Level) {
+ self.level = level;
+ }
+}
+
+impl Logger for TestLogger {
+ fn log(&self, record: &Record) {
+ if self.level >= record.level {
+ println!("{:<5} [{} : {}, {}] {}", record.level.to_string(), record.module_path, record.file, record.line, record.args);
+ }
+ }
+}