tool: add curl command line option --trace-ids

- added and documented --trace-ids to prepend (after the timestamp)
  the transfer and connection identifiers to each verbose log line
- format is [n-m] with `n` being the transfer id and `m` being the
  connection id. In case there is not valid connection id, print 'x'.
- Log calls with a handle that has no transfer id yet, are written
  without any ids.

Closes #11185
This commit is contained in:
Stefan Eissing 2023-06-11 11:02:29 +02:00 committed by Daniel Stenberg
parent e024d5665d
commit f06cc4f85e
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
9 changed files with 73 additions and 14 deletions

View File

@ -64,6 +64,17 @@
curl --trace-ascii d.txt --trace-time http://example.com/ curl --trace-ascii d.txt --trace-time http://example.com/
## See which Transfer
When doing parallel transfers, it is relevant to see which transfer is
doing what. When response headers are received (and logged) you need to
know which transfer these are for.
[`--trace-ids`](https://curl.se/docs/manpage.html#--trace-ids) option
is what you need. It will prepend the transfer and connection identifier
to each trace output line:
curl --trace-ascii d.txt --trace-ids http://example.com/
## See the Response ## See the Response
By default curl sends the response to stdout. You need to redirect it By default curl sends the response to stdout. You need to redirect it

View File

@ -265,6 +265,7 @@ DPAGES = \
tlsv1.d \ tlsv1.d \
tr-encoding.d \ tr-encoding.d \
trace-ascii.d \ trace-ascii.d \
trace-ids.d \
trace-time.d \ trace-time.d \
trace.d \ trace.d \
unix-socket.d \ unix-socket.d \

View File

@ -0,0 +1,12 @@
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: trace-ids
Help: Add transfer and connection identifiers to trace/verbose output
Added: 8.2.0
Category: verbose
Example: --trace-ids --trace-ascii output $URL
See-also: trace verbose
Multi: boolean
Scope: global
---
Prepends the transfer and connection identifiers to each trace or verbose line that curl displays.

View File

@ -7,7 +7,7 @@ Mutexed: verbose trace-ascii
Category: verbose Category: verbose
Example: --trace log.txt $URL Example: --trace log.txt $URL
Added: 7.9.7 Added: 7.9.7
See-also: trace-ascii trace-time See-also: trace-ascii trace-ids trace-time
Multi: single Multi: single
Scope: global Scope: global
--- ---

View File

@ -252,6 +252,7 @@
--tr-encoding 7.21.6 --tr-encoding 7.21.6
--trace 7.9.7 --trace 7.9.7
--trace-ascii 7.9.7 --trace-ascii 7.9.7
--trace-ids 8.2.0
--trace-time 7.14.0 --trace-time 7.14.0
--unix-socket 7.40.0 --unix-socket 7.40.0
--upload-file (-T) 4.0 --upload-file (-T) 4.0

View File

@ -34,7 +34,7 @@
#include "memdebug.h" /* keep this as LAST include */ #include "memdebug.h" /* keep this as LAST include */
static void dump(const char *timebuf, const char *text, static void dump(const char *timebuf, const char *idsbuf, const char *text,
FILE *stream, const unsigned char *ptr, size_t size, FILE *stream, const unsigned char *ptr, size_t size,
trace tracetype, curl_infotype infotype); trace tracetype, curl_infotype infotype);
@ -67,7 +67,8 @@ static const char *hms_for_sec(time_t tv_sec)
return hms_buf; return hms_buf;
} }
static void log_line_start(FILE *log, const char *intro, curl_infotype type) static void log_line_start(FILE *log, const char *timebuf,
const char *idsbuf, curl_infotype type)
{ {
/* /*
* This is the trace look that is similar to what libcurl makes on its * This is the trace look that is similar to what libcurl makes on its
@ -76,12 +77,15 @@ static void log_line_start(FILE *log, const char *intro, curl_infotype type)
static const char * const s_infotype[] = { static const char * const s_infotype[] = {
"* ", "< ", "> ", "{ ", "} ", "{ ", "} " "* ", "< ", "> ", "{ ", "} ", "{ ", "} "
}; };
if(intro && *intro) if((timebuf && *timebuf) || (idsbuf && *idsbuf))
fprintf(log, "%s%s", intro, s_infotype[type]); fprintf(log, "%s%s%s", timebuf, idsbuf, s_infotype[type]);
else else
fputs(s_infotype[type], log); fputs(s_infotype[type], log);
} }
#define TRC_IDS_FORMAT_IDS_1 "[%" CURL_FORMAT_CURL_OFF_T "-x] "
#define TRC_IDS_FORMAT_IDS_2 "[%" CURL_FORMAT_CURL_OFF_T "-%" \
CURL_FORMAT_CURL_OFF_T "] "
/* /*
** callback for CURLOPT_DEBUGFUNCTION ** callback for CURLOPT_DEBUGFUNCTION
*/ */
@ -95,6 +99,13 @@ int tool_debug_cb(CURL *handle, curl_infotype type,
const char *text; const char *text;
struct timeval tv; struct timeval tv;
char timebuf[20]; char timebuf[20];
/* largest signed 64bit is: 9,223,372,036,854,775,807
* max length in decimal: 1 + (6*3) = 19
* formatted via TRC_IDS_FORMAT_IDS_2 this becomes 2 + 19 + 1 + 19 + 2 = 43
* negative xfer-id are not printed, negative conn-ids use TRC_IDS_FORMAT_1
*/
char idsbuf[60];
curl_off_t xfer_id, conn_id;
(void)handle; /* not used */ (void)handle; /* not used */
@ -106,6 +117,20 @@ int tool_debug_cb(CURL *handle, curl_infotype type,
else else
timebuf[0] = 0; timebuf[0] = 0;
if(handle && config->traceids &&
!curl_easy_getinfo(handle, CURLINFO_XFER_ID, &xfer_id) && xfer_id >= 0) {
if(!curl_easy_getinfo(handle, CURLINFO_CONN_ID, &conn_id) &&
conn_id >= 0) {
msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_2,
xfer_id, conn_id);
}
else {
msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_1, xfer_id);
}
}
else
idsbuf[0] = 0;
if(!config->trace_stream) { if(!config->trace_stream) {
/* open for append */ /* open for append */
if(!strcmp("-", config->trace_dump)) if(!strcmp("-", config->trace_dump))
@ -139,7 +164,7 @@ int tool_debug_cb(CURL *handle, curl_infotype type,
for(i = 0; i < size - 1; i++) { for(i = 0; i < size - 1; i++) {
if(data[i] == '\n') { /* LF */ if(data[i] == '\n') { /* LF */
if(!newl) { if(!newl) {
log_line_start(output, timebuf, type); log_line_start(output, timebuf, idsbuf, type);
} }
(void)fwrite(data + st, i - st + 1, 1, output); (void)fwrite(data + st, i - st + 1, 1, output);
st = i + 1; st = i + 1;
@ -147,7 +172,7 @@ int tool_debug_cb(CURL *handle, curl_infotype type,
} }
} }
if(!newl) if(!newl)
log_line_start(output, timebuf, type); log_line_start(output, timebuf, idsbuf, type);
(void)fwrite(data + st, i - st + 1, 1, output); (void)fwrite(data + st, i - st + 1, 1, output);
} }
newl = (size && (data[size - 1] != '\n')) ? TRUE : FALSE; newl = (size && (data[size - 1] != '\n')) ? TRUE : FALSE;
@ -156,7 +181,7 @@ int tool_debug_cb(CURL *handle, curl_infotype type,
case CURLINFO_TEXT: case CURLINFO_TEXT:
case CURLINFO_HEADER_IN: case CURLINFO_HEADER_IN:
if(!newl) if(!newl)
log_line_start(output, timebuf, type); log_line_start(output, timebuf, idsbuf, type);
(void)fwrite(data, size, 1, output); (void)fwrite(data, size, 1, output);
newl = (size && (data[size - 1] != '\n')) ? TRUE : FALSE; newl = (size && (data[size - 1] != '\n')) ? TRUE : FALSE;
traced_data = FALSE; traced_data = FALSE;
@ -172,7 +197,7 @@ int tool_debug_cb(CURL *handle, curl_infotype type,
function */ function */
if(!config->isatty || ((output != stderr) && (output != stdout))) { if(!config->isatty || ((output != stderr) && (output != stdout))) {
if(!newl) if(!newl)
log_line_start(output, timebuf, type); log_line_start(output, timebuf, idsbuf, type);
fprintf(output, "[%zu bytes data]\n", size); fprintf(output, "[%zu bytes data]\n", size);
newl = FALSE; newl = FALSE;
traced_data = TRUE; traced_data = TRUE;
@ -190,7 +215,7 @@ int tool_debug_cb(CURL *handle, curl_infotype type,
switch(type) { switch(type) {
case CURLINFO_TEXT: case CURLINFO_TEXT:
fprintf(output, "%s== Info: %.*s", timebuf, (int)size, data); fprintf(output, "%s%s== Info: %.*s", timebuf, idsbuf, (int)size, data);
/* FALLTHROUGH */ /* FALLTHROUGH */
default: /* in case a new one is introduced to shock us */ default: /* in case a new one is introduced to shock us */
return 0; return 0;
@ -215,12 +240,12 @@ int tool_debug_cb(CURL *handle, curl_infotype type,
break; break;
} }
dump(timebuf, text, output, (unsigned char *) data, size, config->tracetype, dump(timebuf, idsbuf, text, output, (unsigned char *) data, size,
type); config->tracetype, type);
return 0; return 0;
} }
static void dump(const char *timebuf, const char *text, static void dump(const char *timebuf, const char *idsbuf, const char *text,
FILE *stream, const unsigned char *ptr, size_t size, FILE *stream, const unsigned char *ptr, size_t size,
trace tracetype, curl_infotype infotype) trace tracetype, curl_infotype infotype)
{ {
@ -233,7 +258,8 @@ static void dump(const char *timebuf, const char *text,
/* without the hex output, we can fit more on screen */ /* without the hex output, we can fit more on screen */
width = 0x40; width = 0x40;
fprintf(stream, "%s%s, %zu bytes (0x%zx)\n", timebuf, text, size, size); fprintf(stream, "%s%s%s, %zu bytes (0x%zx)\n", timebuf, idsbuf,
text, size, size);
for(i = 0; i < size; i += width) { for(i = 0; i < size; i += width) {

View File

@ -308,6 +308,7 @@ struct GlobalConfig {
bool trace_fopened; bool trace_fopened;
trace tracetype; trace tracetype;
bool tracetime; /* include timestamp? */ bool tracetime; /* include timestamp? */
bool traceids; /* include xfer-/conn-id? */
int progressmode; /* CURL_PROGRESS_BAR / CURL_PROGRESS_STATS */ int progressmode; /* CURL_PROGRESS_BAR / CURL_PROGRESS_STATS */
char *libcurl; /* Output libcurl code to this file name */ char *libcurl; /* Output libcurl code to this file name */
bool fail_early; /* exit on first transfer error */ bool fail_early; /* exit on first transfer error */

View File

@ -205,6 +205,7 @@ static const struct LongShort aliases[]= {
{"$Z", "compressed-ssh", ARG_BOOL}, {"$Z", "compressed-ssh", ARG_BOOL},
{"$~", "happy-eyeballs-timeout-ms", ARG_STRING}, {"$~", "happy-eyeballs-timeout-ms", ARG_STRING},
{"$!", "retry-all-errors", ARG_BOOL}, {"$!", "retry-all-errors", ARG_BOOL},
{"$%", "trace-ids", ARG_BOOL},
{"0", "http1.0", ARG_NONE}, {"0", "http1.0", ARG_NONE},
{"01", "http1.1", ARG_NONE}, {"01", "http1.1", ARG_NONE},
{"02", "http2", ARG_NONE}, {"02", "http2", ARG_NONE},
@ -1407,6 +1408,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
return err; return err;
/* 0 is a valid value for this timeout */ /* 0 is a valid value for this timeout */
break; break;
case '%': /* --trace-ids */
global->traceids = toggle;
break;
} }
break; break;
case '#': case '#':

View File

@ -759,6 +759,9 @@ const struct helptxt helptext[] = {
{" --trace-ascii <file>", {" --trace-ascii <file>",
"Like --trace, but without hex output", "Like --trace, but without hex output",
CURLHELP_VERBOSE}, CURLHELP_VERBOSE},
{" --trace-ids",
"Add transfer/connection identifiers to trace/verbose output",
CURLHELP_VERBOSE},
{" --trace-time", {" --trace-time",
"Add time stamps to trace/verbose output", "Add time stamps to trace/verbose output",
CURLHELP_VERBOSE}, CURLHELP_VERBOSE},