Collect and print stats about HTTP status code
This commit is contained in:
@@ -303,6 +303,21 @@ LLAtomicU32 Stats::AICurlEasyRequestStateMachine_count;
|
|||||||
LLAtomicU32 Stats::BufferedCurlEasyRequest_count;
|
LLAtomicU32 Stats::BufferedCurlEasyRequest_count;
|
||||||
LLAtomicU32 Stats::ResponderBase_count;
|
LLAtomicU32 Stats::ResponderBase_count;
|
||||||
LLAtomicU32 Stats::ThreadSafeBufferedCurlEasyRequest_count;
|
LLAtomicU32 Stats::ThreadSafeBufferedCurlEasyRequest_count;
|
||||||
|
LLAtomicU32 Stats::status_count[100];
|
||||||
|
LLAtomicU32 Stats::llsd_body_count;
|
||||||
|
LLAtomicU32 Stats::llsd_body_parse_error;
|
||||||
|
LLAtomicU32 Stats::raw_body_count;
|
||||||
|
|
||||||
|
U32 Stats::status2index(U32 status)
|
||||||
|
{
|
||||||
|
llassert_always(status >= 100 && status < 600 && (status % 100) < 20); // Max value 519.
|
||||||
|
return (status - 100) / 100 * 20 + status % 100; // Returns 0..99 (for status 100..519).
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 Stats::index2status(U32 index)
|
||||||
|
{
|
||||||
|
return 100 + (index / 20) * 100 + index % 20;
|
||||||
|
}
|
||||||
|
|
||||||
// MAIN-THREAD
|
// MAIN-THREAD
|
||||||
void initCurl(void)
|
void initCurl(void)
|
||||||
@@ -448,6 +463,25 @@ void Stats::print(void)
|
|||||||
llinfos_nf << " Current number of AICurlEasyRequestStateMachine objects: " << AICurlEasyRequestStateMachine_count << llendl;
|
llinfos_nf << " Current number of AICurlEasyRequestStateMachine objects: " << AICurlEasyRequestStateMachine_count << llendl;
|
||||||
#endif
|
#endif
|
||||||
llinfos_nf << " Current number of Responders: " << ResponderBase_count << llendl;
|
llinfos_nf << " Current number of Responders: " << ResponderBase_count << llendl;
|
||||||
|
llinfos_nf << " Received HTTP bodies LLSD / LLSD parse errors / non-LLSD: " << llsd_body_count << "/" << llsd_body_parse_error << "/" << raw_body_count << llendl;
|
||||||
|
llinfos_nf << " Received HTTP status codes: status (count) [...]: ";
|
||||||
|
bool first = true;
|
||||||
|
for (U32 index = 0; index < 100; ++index)
|
||||||
|
{
|
||||||
|
if (status_count[index] > 0)
|
||||||
|
{
|
||||||
|
if (!first)
|
||||||
|
{
|
||||||
|
llcont << ", ";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
llcont << index2status(index) << " (" << status_count[index] << ')';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
llcont << llendl;
|
||||||
llinfos_nf << "========= END OF CURL STATS =========" << llendl;
|
llinfos_nf << "========= END OF CURL STATS =========" << llendl;
|
||||||
// Leak tests.
|
// Leak tests.
|
||||||
// There is one easy handle per CurlEasyHandle, and BufferedCurlEasyRequest is derived from that.
|
// There is one easy handle per CurlEasyHandle, and BufferedCurlEasyRequest is derived from that.
|
||||||
|
|||||||
@@ -140,8 +140,14 @@ struct Stats {
|
|||||||
static LLAtomicU32 BufferedCurlEasyRequest_count;
|
static LLAtomicU32 BufferedCurlEasyRequest_count;
|
||||||
static LLAtomicU32 ResponderBase_count;
|
static LLAtomicU32 ResponderBase_count;
|
||||||
static LLAtomicU32 ThreadSafeBufferedCurlEasyRequest_count;
|
static LLAtomicU32 ThreadSafeBufferedCurlEasyRequest_count;
|
||||||
|
static LLAtomicU32 status_count[100];
|
||||||
|
static LLAtomicU32 llsd_body_count;
|
||||||
|
static LLAtomicU32 llsd_body_parse_error;
|
||||||
|
static LLAtomicU32 raw_body_count;
|
||||||
|
|
||||||
static void print(void);
|
static void print(void);
|
||||||
|
static U32 status2index(U32 status);
|
||||||
|
static U32 index2status(U32 index);
|
||||||
};
|
};
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -2043,6 +2043,7 @@ void BufferedCurlEasyRequest::setStatusAndReason(U32 status, std::string const&
|
|||||||
{
|
{
|
||||||
mStatus = status;
|
mStatus = status;
|
||||||
mReason = reason;
|
mReason = reason;
|
||||||
|
AICurlInterface::Stats::status_count[AICurlInterface::Stats::status2index(mStatus)]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BufferedCurlEasyRequest::processOutput(void)
|
void BufferedCurlEasyRequest::processOutput(void)
|
||||||
|
|||||||
@@ -264,73 +264,76 @@ void LLHTTPClient::get(std::string const& url, LLSD const& query, ResponderPtr r
|
|||||||
|
|
||||||
LLHTTPClient::ResponderBase::ResponderBase(void) : mReferenceCount(0), mCode(CURLE_FAILED_INIT), mFinished(false)
|
LLHTTPClient::ResponderBase::ResponderBase(void) : mReferenceCount(0), mCode(CURLE_FAILED_INIT), mFinished(false)
|
||||||
{
|
{
|
||||||
DoutEntering(dc::curl, "AICurlInterface::Responder() with this = " << (void*)this);
|
DoutEntering(dc::curl, "AICurlInterface::Responder() with this = " << (void*)this);
|
||||||
AICurlInterface::Stats::ResponderBase_count++;
|
AICurlInterface::Stats::ResponderBase_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
LLHTTPClient::ResponderBase::~ResponderBase()
|
LLHTTPClient::ResponderBase::~ResponderBase()
|
||||||
{
|
{
|
||||||
DoutEntering(dc::curl, "AICurlInterface::ResponderBase::~ResponderBase() with this = " << (void*)this << "; mReferenceCount = " << mReferenceCount);
|
DoutEntering(dc::curl, "AICurlInterface::ResponderBase::~ResponderBase() with this = " << (void*)this << "; mReferenceCount = " << mReferenceCount);
|
||||||
llassert(mReferenceCount == 0);
|
llassert(mReferenceCount == 0);
|
||||||
--AICurlInterface::Stats::ResponderBase_count;
|
--AICurlInterface::Stats::ResponderBase_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLHTTPClient::ResponderBase::setURL(std::string const& url)
|
void LLHTTPClient::ResponderBase::setURL(std::string const& url)
|
||||||
{
|
{
|
||||||
// setURL is called from llhttpclient.cpp (request()), before calling any of the below (of course).
|
// setURL is called from llhttpclient.cpp (request()), before calling any of the below (of course).
|
||||||
// We don't need locking here therefore; it's a case of initializing before use.
|
// We don't need locking here therefore; it's a case of initializing before use.
|
||||||
mURL = url;
|
mURL = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
AIHTTPTimeoutPolicy const& LLHTTPClient::ResponderBase::getHTTPTimeoutPolicy(void) const
|
AIHTTPTimeoutPolicy const& LLHTTPClient::ResponderBase::getHTTPTimeoutPolicy(void) const
|
||||||
{
|
{
|
||||||
return AIHTTPTimeoutPolicy::getDebugSettingsCurlTimeout();
|
return AIHTTPTimeoutPolicy::getDebugSettingsCurlTimeout();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLHTTPClient::ResponderBase::decode_llsd_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, LLSD& content)
|
void LLHTTPClient::ResponderBase::decode_llsd_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, LLSD& content)
|
||||||
{
|
{
|
||||||
// If the status indicates success (and we get here) then we expect the body to be LLSD.
|
AICurlInterface::Stats::llsd_body_count++;
|
||||||
bool const should_be_llsd = (200 <= status && status < 300);
|
// If the status indicates success (and we get here) then we expect the body to be LLSD.
|
||||||
if (should_be_llsd)
|
bool const should_be_llsd = (200 <= status && status < 300);
|
||||||
{
|
if (should_be_llsd)
|
||||||
LLBufferStream istr(channels, buffer.get());
|
|
||||||
if (LLSDSerialize::fromXML(content, istr) == LLSDParser::PARSE_FAILURE)
|
|
||||||
{
|
{
|
||||||
// Unfortunately we can't show the body of the message... I think this is a pretty serious error
|
LLBufferStream istr(channels, buffer.get());
|
||||||
// though, so if this ever happens it has to be investigated by making a copy of the buffer
|
if (LLSDSerialize::fromXML(content, istr) == LLSDParser::PARSE_FAILURE)
|
||||||
// before serializing it, as is done below.
|
{
|
||||||
llwarns << "Failed to deserialize LLSD. " << mURL << " [" << status << "]: " << reason << llendl;
|
// Unfortunately we can't show the body of the message... I think this is a pretty serious error
|
||||||
|
// though, so if this ever happens it has to be investigated by making a copy of the buffer
|
||||||
|
// before serializing it, as is done below.
|
||||||
|
llwarns << "Failed to deserialize LLSD. " << mURL << " [" << status << "]: " << reason << llendl;
|
||||||
|
AICurlInterface::Stats::llsd_body_parse_error++;
|
||||||
|
}
|
||||||
|
// LLSDSerialize::fromXML destructed buffer, we can't initialize content now.
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
// LLSDSerialize::fromXML destructed buffer, we can't initialize content now.
|
// Put the body in content as-is.
|
||||||
return;
|
std::stringstream ss;
|
||||||
}
|
buffer->writeChannelTo(ss, channels.in());
|
||||||
// Put the body in content as-is.
|
content = ss.str();
|
||||||
std::stringstream ss;
|
|
||||||
buffer->writeChannelTo(ss, channels.in());
|
|
||||||
content = ss.str();
|
|
||||||
#ifdef SHOW_ASSERT
|
#ifdef SHOW_ASSERT
|
||||||
if (!should_be_llsd)
|
if (!should_be_llsd)
|
||||||
{
|
|
||||||
char const* str = ss.str().c_str();
|
|
||||||
// Make sure that the server indeed never returns LLSD as body when the http status is an error.
|
|
||||||
LLSD dummy;
|
|
||||||
bool server_sent_llsd_with_http_error =
|
|
||||||
strncmp(str, "<!DOCTYPE", 9) && // LLSD does never start with "<!"; short circuits 97% of the replies.
|
|
||||||
strncmp(str, "cap not found:", 14) && // Most of the other 3%.
|
|
||||||
str[0] && // Empty happens too and aint LLSD either.
|
|
||||||
strncmp(str, "Not Found", 9) &&
|
|
||||||
LLSDSerialize::fromXML(dummy, ss) > 0;
|
|
||||||
if (server_sent_llsd_with_http_error)
|
|
||||||
{
|
{
|
||||||
llwarns << "The server sent us a response with http status " << status << " and LLSD(!) body: \"" << ss.str() << "\"!" << llendl;
|
char const* str = ss.str().c_str();
|
||||||
|
// Make sure that the server indeed never returns LLSD as body when the http status is an error.
|
||||||
|
LLSD dummy;
|
||||||
|
bool server_sent_llsd_with_http_error =
|
||||||
|
strncmp(str, "<!DOCTYPE", 9) && // LLSD does never start with "<!"; short circuits 97% of the replies.
|
||||||
|
strncmp(str, "cap not found:", 14) && // Most of the other 3%.
|
||||||
|
str[0] && // Empty happens too and aint LLSD either.
|
||||||
|
strncmp(str, "Not Found", 9) &&
|
||||||
|
LLSDSerialize::fromXML(dummy, ss) > 0;
|
||||||
|
if (server_sent_llsd_with_http_error)
|
||||||
|
{
|
||||||
|
llwarns << "The server sent us a response with http status " << status << " and LLSD(!) body: \"" << ss.str() << "\"!" << llendl;
|
||||||
|
}
|
||||||
|
llassert(!server_sent_llsd_with_http_error);
|
||||||
}
|
}
|
||||||
llassert(!server_sent_llsd_with_http_error);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLHTTPClient::ResponderBase::decode_raw_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, std::string& content)
|
void LLHTTPClient::ResponderBase::decode_raw_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, std::string& content)
|
||||||
{
|
{
|
||||||
|
AICurlInterface::Stats::raw_body_count++;
|
||||||
LLMutexLock lock(buffer->getMutex());
|
LLMutexLock lock(buffer->getMutex());
|
||||||
LLBufferArray::const_segment_iterator_t const end = buffer->endSegment();
|
LLBufferArray::const_segment_iterator_t const end = buffer->endSegment();
|
||||||
for (LLBufferArray::const_segment_iterator_t iter = buffer->beginSegment(); iter != end; ++iter)
|
for (LLBufferArray::const_segment_iterator_t iter = buffer->beginSegment(); iter != end; ++iter)
|
||||||
|
|||||||
Reference in New Issue
Block a user