One thing to decide would be whether you want to have hierarchical levels for
debugging per subsystem (you call them "events" I think), or whether to have a
bitmask-like value to enable or disable specific classes of messages (like
openLDAP does it).
Personally I think that short debug output is perferrable to long output. With
commercial software I have hjad several cases where support really wanted me to
capture more than a GB of logs, where the logs contained really every stupid thing
the program did. In the end they said they could not find the problem, because
they did not log that specific case... 8-(
Regards,
Ulrich
> --
>
> You received this message because you are subscribed to the Google Groups "open-iscsi" group.
> To post to this group, send email to open-...@googlegroups.com.
> To unsubscribe from this group, send email to open-iscsi+...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/open-iscsi?hl=en.
>
>
I've started working on the new logging. I've started with iscsi_tcp.
Here's a glance of the general idea. If you have comments on the
general implementation, let's discuss them now. Later, it will be much
more difficult for me.
Here it is:
Added the following code in libiscsi.h:
#define iscsi_log(log_level, dev, dbg_fmt, arg...) \
do { \
char *log_level_str; \
switch (log_level) { \
case ISCSI_LOG_ERROR: \
log_level_str = "ERROR"; \
break; \
case ISCSI_LOG_WARN: \
log_level_str = "WARN"; \
break; \
case ISCSI_LOG_INFO: \
log_level_str = "INFO"; \
break; \
case ISCSI_LOG_DEBUG: \
log_level_str = "DEBUG"; \
break; \
case ISCSI_LOG_TRACE: \
log_level_str = "TRACE"; \
break; \
} \
if (log_level > ISCSI_LOG_INFO) { \
if (dev) { \
dev_printk(KERN_DEBUG, \
(struct device *)dev, \
"%s:%d (%s) " dbg_fmt "\n", \
__func__, __LINE__, \
log_level_str, ##arg); \
} else { \
printk(KERN_DEBUG \
"%s:%d (%s) " dbg_fmt "\n", \
__func__, __LINE__, \
log_level_str, ##arg); \
} \
} else { \
if (dev) { \
dev_printk(KERN_INFO, \
(struct device *)dev, \
"%s:%d (%s) " dbg_fmt "\n", \
__func__, __LINE__, \
log_level_str, ##arg); \
} else { \
printk(KERN_INFO \
"%s:%d (%s) " dbg_fmt "\n", \
__func__, __LINE__, \
log_level_str, ##arg); \
} \
} \
} while (0);
added a new iscsi_log.h file:
enum iscsi_log_level {
ISCSI_LOG_ERROR = 1,
ISCSI_LOG_WARN,
ISCSI_LOG_INFO,
ISCSI_LOG_DEBUG,
ISCSI_LOG_TRACE
};
and in iscsi_tcp.c:
/* Logging contexts */
struct {
int general;
int conn;
} iscsi_sw_tcp_log_ctxt = {ISCSI_LOG_INFO, ISCSI_LOG_INFO};
enum iscsi_sw_tcp_ctxt {
ISCSI_SW_TCP_CTXT_GENERAL = 1,
ISCSI_SW_TCP_CTXT_CONN,
};
module_param_named(general_log_ctxt, iscsi_sw_tcp_log_ctxt.general, int,
S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(general_log_ctxt, "blah blah - general");
module_param_named(conn_log_ctxt, iscsi_sw_tcp_log_ctxt.conn, int,
S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(conn_log_ctxt, "blah blah - conn");
#define _iscsi_sw_tcp_log(log_level, ctxt, dev, dbg_fmt, arg...) \
do { \
switch (ctxt) { \
case ISCSI_SW_TCP_CTXT_GENERAL: \
if (log_level <= iscsi_sw_tcp_log_ctxt.general) \
iscsi_log(log_level, dev, dbg_fmt, \
##arg); \
break; \
case ISCSI_SW_TCP_CTXT_CONN: \
if (log_level <= iscsi_sw_tcp_log_ctxt.conn) \
iscsi_log(log_level, dev, dbg_fmt, \
##arg); \
break; \
} \
} while (0);
#define iscsi_sw_tcp_log(log_level, ctxt, dbg_fmt, arg...) \
do { \
_iscsi_sw_tcp_log(log_level, ctxt, NULL, dbg_fmt, \
##arg); \
} while (0);
#define iscsi_sw_tcp_conn_log(log_level, ctxt, conn, dbg_fmt, arg...) \
do { \
struct device *dev; \
dev = &((struct iscsi_conn *)conn)->cls_conn->dev; \
_iscsi_sw_tcp_log(log_level, ctxt, dev, dbg_fmt, arg); \
} while (0);
#define iscsi_sw_tcp_sess_log(log_level, ctxt, sess, dbg_fmt, arg...) \
do { \
struct device *dev; \
dev = &((struct iscsi_session *)sess)->cls_session->dev;\
_iscsi_sw_tcp_log(log_level, ctxt, dev, dbg_fmt, arg); \
} while (0);
so now, instead of doing the following in iscsi_sw_tcp_send_hdr_done():
ISCSI_SW_TCP_DBG(tcp_conn->iscsi_conn,
"Header done. Next segment size %u total_size %u\n",
tcp_sw_conn->out.segment.size,
tcp_sw_conn->out.segment.total_size);
we will do the following:
iscsi_sw_tcp_conn_log(ISCSI_LOG_INFO, ISCSI_SW_TCP_CTXT_CONN,
tcp_conn->iscsi_conn,
"Header done. Next segment size %u total_size %u\n",
tcp_sw_conn->out.segment.size,
tcp_sw_conn->out.segment.total_size);
Hi!
I wonder whether the #define could be replaced with an inline function.
The readability would be much better, and the code should be more or
less the same, unless you need special macro processing. For code size
we could even try to make it a "normal" routine (i.e. not inlined). The
performance might suffer a little bit, however.
Also: With "-O3" gcc usually automatically inlines short "static"
(locally defined?) routines.
Regards,
Ulrich
[...]
> Here it is:
>
> Added the following code in libiscsi.h:
>
> #define iscsi_log(log_level, dev, dbg_fmt, arg...) \
> do { \
[...]
> } while (0);
[...]------------
Ulrich Windl Klinikum der Universitaet Regensburg
Rechenzentrum DV-med Franz-Josef-Strauss-Allee 11
Tel: +49 941 944-5879 D-93053 Regensburg
FAX: +49 941 944-5882
"The bad PC memory subsystems are really bad." (Linus Torvalds,
19.04.1996)
"Unknown DHCP option 0 length 255" (Windows/NT Server 3.51)
"Oh, it's Visibly BASIC!" -- U. Windl
We can make it inline instead of using a macro. I used macros because
this is what we had till now, and I didn't want to change that. The
only problem with inline functions is that it's up to the compiler to
decide if the function will be inlined. This may affect performance in
some cases.
Erez
One more thing: take a look at _iscsi_sw_tcp_log. If we have a large
amount of contexts in the module (connection, session, error handling,
data transfer, socket, module etc), the switch block may become quite
large. I don't know if the compiler will decide to make such a
function inline.
Erez