mirror of https://github.com/Icinga/icinga2.git
/v1/debug/malloc_info: call malloc_info(3) if available
The GNU libc function malloc_info(3) provides memory allocation and usage statistics of Icinga 2 itself.
This commit is contained in:
parent
b6b2f72055
commit
f3c7ac11e9
|
@ -365,6 +365,7 @@ check_function_exists(vfork HAVE_VFORK)
|
||||||
check_function_exists(backtrace_symbols HAVE_BACKTRACE_SYMBOLS)
|
check_function_exists(backtrace_symbols HAVE_BACKTRACE_SYMBOLS)
|
||||||
check_function_exists(pipe2 HAVE_PIPE2)
|
check_function_exists(pipe2 HAVE_PIPE2)
|
||||||
check_function_exists(nice HAVE_NICE)
|
check_function_exists(nice HAVE_NICE)
|
||||||
|
check_function_exists(malloc_info HAVE_MALLOC_INFO)
|
||||||
check_library_exists(dl dladdr "dlfcn.h" HAVE_DLADDR)
|
check_library_exists(dl dladdr "dlfcn.h" HAVE_DLADDR)
|
||||||
check_library_exists(execinfo backtrace_symbols "" HAVE_LIBEXECINFO)
|
check_library_exists(execinfo backtrace_symbols "" HAVE_LIBEXECINFO)
|
||||||
check_include_file_cxx(cxxabi.h HAVE_CXXABI_H)
|
check_include_file_cxx(cxxabi.h HAVE_CXXABI_H)
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#cmakedefine HAVE_LIBEXECINFO
|
#cmakedefine HAVE_LIBEXECINFO
|
||||||
#cmakedefine HAVE_CXXABI_H
|
#cmakedefine HAVE_CXXABI_H
|
||||||
#cmakedefine HAVE_NICE
|
#cmakedefine HAVE_NICE
|
||||||
|
#cmakedefine HAVE_MALLOC_INFO
|
||||||
#cmakedefine HAVE_EDITLINE
|
#cmakedefine HAVE_EDITLINE
|
||||||
#cmakedefine HAVE_SYSTEMD
|
#cmakedefine HAVE_SYSTEMD
|
||||||
|
|
||||||
|
|
|
@ -288,6 +288,7 @@ Available permissions for specific URL endpoints:
|
||||||
config/query | /v1/config | No | 1
|
config/query | /v1/config | No | 1
|
||||||
config/modify | /v1/config | No | 512
|
config/modify | /v1/config | No | 512
|
||||||
console | /v1/console | No | 1
|
console | /v1/console | No | 1
|
||||||
|
debug | /v1/debug | No | 1
|
||||||
events/<type> | /v1/events | No | 1
|
events/<type> | /v1/events | No | 1
|
||||||
objects/query/<type> | /v1/objects | Yes | 1
|
objects/query/<type> | /v1/objects | Yes | 1
|
||||||
objects/create/<type> | /v1/objects | No | 1
|
objects/create/<type> | /v1/objects | No | 1
|
||||||
|
@ -2502,6 +2503,72 @@ curl -k -s -S -i -u root:icinga -H 'Accept: application/json' \
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Memory Usage Analysis <a id="icinga2-api-memory"></a>
|
||||||
|
|
||||||
|
The GNU libc function `malloc_info(3)` provides memory allocation and usage
|
||||||
|
statistics of Icinga 2 itself. You can call it directly by sending a `GET`
|
||||||
|
request to the URL endpoint `/v1/debug/malloc_info`.
|
||||||
|
|
||||||
|
The [API permission](12-icinga2-api.md#icinga2-api-permissions) `debug` is required.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -k -s -S -i -u root:icinga https://localhost:5665/v1/debug/malloc_info
|
||||||
|
```
|
||||||
|
|
||||||
|
In contrast to other API endpoints, the response is not JSON,
|
||||||
|
but the raw XML output from `malloc_info(3)`. See also the
|
||||||
|
[glibc malloc(3) internals](https://sourceware.org/glibc/wiki/MallocInternals).
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<malloc version="1">
|
||||||
|
<heap nr="0">
|
||||||
|
<sizes>
|
||||||
|
<size from="33" to="48" total="96" count="2"/>
|
||||||
|
<size from="49" to="64" total="192" count="3"/>
|
||||||
|
<size from="65" to="80" total="80" count="1"/>
|
||||||
|
<unsorted from="84817" to="84817" total="84817" count="1"/>
|
||||||
|
</sizes>
|
||||||
|
<total type="fast" count="6" size="368"/>
|
||||||
|
<total type="rest" count="2" size="859217"/>
|
||||||
|
<system type="current" size="7409664"/>
|
||||||
|
<system type="max" size="7409664"/>
|
||||||
|
<aspace type="total" size="7409664"/>
|
||||||
|
<aspace type="mprotect" size="7409664"/>
|
||||||
|
</heap>
|
||||||
|
<!-- ... -->
|
||||||
|
<heap nr="30">
|
||||||
|
<sizes>
|
||||||
|
<size from="17" to="32" total="96" count="3"/>
|
||||||
|
<size from="33" to="48" total="576" count="12"/>
|
||||||
|
<size from="49" to="64" total="64" count="1"/>
|
||||||
|
<size from="97" to="112" total="3584" count="32"/>
|
||||||
|
<size from="49" to="49" total="98" count="2"/>
|
||||||
|
<size from="81" to="81" total="810" count="10"/>
|
||||||
|
<size from="257" to="257" total="2827" count="11"/>
|
||||||
|
<size from="689" to="689" total="689" count="1"/>
|
||||||
|
<size from="705" to="705" total="705" count="1"/>
|
||||||
|
<unsorted from="81" to="81" total="81" count="1"/>
|
||||||
|
</sizes>
|
||||||
|
<total type="fast" count="48" size="4320"/>
|
||||||
|
<total type="rest" count="27" size="118618"/>
|
||||||
|
<system type="current" size="135168"/>
|
||||||
|
<system type="max" size="135168"/>
|
||||||
|
<aspace type="total" size="135168"/>
|
||||||
|
<aspace type="mprotect" size="135168"/>
|
||||||
|
<aspace type="subheaps" size="1"/>
|
||||||
|
</heap>
|
||||||
|
<total type="fast" count="938" size="79392"/>
|
||||||
|
<total type="rest" count="700" size="4409469"/>
|
||||||
|
<total type="mmap" count="0" size="0"/>
|
||||||
|
<system type="current" size="15114240"/>
|
||||||
|
<system type="max" size="15114240"/>
|
||||||
|
<aspace type="total" size="15114240"/>
|
||||||
|
<aspace type="mprotect" size="15114240"/>
|
||||||
|
</malloc>
|
||||||
|
```
|
||||||
|
|
||||||
## API Clients <a id="icinga2-api-clients"></a>
|
## API Clients <a id="icinga2-api-clients"></a>
|
||||||
|
|
||||||
After its initial release in 2015, community members
|
After its initial release in 2015, community members
|
||||||
|
|
|
@ -32,6 +32,7 @@ set(remote_SOURCES
|
||||||
infohandler.cpp infohandler.hpp
|
infohandler.cpp infohandler.hpp
|
||||||
jsonrpc.cpp jsonrpc.hpp
|
jsonrpc.cpp jsonrpc.hpp
|
||||||
jsonrpcconnection.cpp jsonrpcconnection.hpp jsonrpcconnection-heartbeat.cpp jsonrpcconnection-pki.cpp
|
jsonrpcconnection.cpp jsonrpcconnection.hpp jsonrpcconnection-heartbeat.cpp jsonrpcconnection-pki.cpp
|
||||||
|
mallocinfohandler.cpp mallocinfohandler.hpp
|
||||||
messageorigin.cpp messageorigin.hpp
|
messageorigin.cpp messageorigin.hpp
|
||||||
modifyobjecthandler.cpp modifyobjecthandler.hpp
|
modifyobjecthandler.cpp modifyobjecthandler.hpp
|
||||||
objectqueryhandler.cpp objectqueryhandler.hpp
|
objectqueryhandler.cpp objectqueryhandler.hpp
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
/* Icinga 2 | (c) 2024 Icinga GmbH | GPLv2+ */
|
||||||
|
|
||||||
|
#include "base/defer.hpp"
|
||||||
|
#include "remote/filterutility.hpp"
|
||||||
|
#include "remote/httputility.hpp"
|
||||||
|
#include "remote/mallocinfohandler.hpp"
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#ifdef HAVE_MALLOC_INFO
|
||||||
|
# include <errno.h>
|
||||||
|
# include <malloc.h>
|
||||||
|
#endif /* HAVE_MALLOC_INFO */
|
||||||
|
|
||||||
|
using namespace icinga;
|
||||||
|
|
||||||
|
REGISTER_URLHANDLER("/v1/debug/malloc_info", MallocInfoHandler);
|
||||||
|
|
||||||
|
bool MallocInfoHandler::HandleRequest(
|
||||||
|
AsioTlsStream&,
|
||||||
|
const ApiUser::Ptr& user,
|
||||||
|
boost::beast::http::request<boost::beast::http::string_body>& request,
|
||||||
|
const Url::Ptr& url,
|
||||||
|
boost::beast::http::response<boost::beast::http::string_body>& response,
|
||||||
|
const Dictionary::Ptr& params,
|
||||||
|
boost::asio::yield_context&,
|
||||||
|
HttpServerConnection&
|
||||||
|
)
|
||||||
|
{
|
||||||
|
namespace http = boost::beast::http;
|
||||||
|
|
||||||
|
if (url->GetPath().size() != 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.method() != http::verb::get) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterUtility::CheckPermission(user, "debug");
|
||||||
|
|
||||||
|
#ifndef HAVE_MALLOC_INFO
|
||||||
|
HttpUtility::SendJsonError(response, params, 501, "malloc_info(3) not available.");
|
||||||
|
#else /* HAVE_MALLOC_INFO */
|
||||||
|
char* buf = nullptr;
|
||||||
|
size_t bufSize = 0;
|
||||||
|
FILE* f = nullptr;
|
||||||
|
|
||||||
|
Defer release ([&f, &buf]() {
|
||||||
|
if (f) {
|
||||||
|
(void)fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
});
|
||||||
|
|
||||||
|
f = open_memstream(&buf, &bufSize);
|
||||||
|
|
||||||
|
if (!f) {
|
||||||
|
auto error (errno);
|
||||||
|
|
||||||
|
BOOST_THROW_EXCEPTION(posix_error()
|
||||||
|
<< boost::errinfo_api_function("open_memstream")
|
||||||
|
<< boost::errinfo_errno(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (malloc_info(0, f)) {
|
||||||
|
auto error (errno);
|
||||||
|
|
||||||
|
BOOST_THROW_EXCEPTION(posix_error()
|
||||||
|
<< boost::errinfo_api_function("malloc_info")
|
||||||
|
<< boost::errinfo_errno(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto closeErr (fclose(f));
|
||||||
|
f = nullptr;
|
||||||
|
|
||||||
|
if (closeErr) {
|
||||||
|
auto error (errno);
|
||||||
|
|
||||||
|
BOOST_THROW_EXCEPTION(posix_error()
|
||||||
|
<< boost::errinfo_api_function("fclose")
|
||||||
|
<< boost::errinfo_errno(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
response.result(200);
|
||||||
|
response.set(http::field::content_type, "application/xml");
|
||||||
|
response.body() = std::string(buf, bufSize);
|
||||||
|
response.content_length(response.body().size());
|
||||||
|
#endif /* HAVE_MALLOC_INFO */
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/* Icinga 2 | (c) 2024 Icinga GmbH | GPLv2+ */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "remote/httphandler.hpp"
|
||||||
|
|
||||||
|
namespace icinga
|
||||||
|
{
|
||||||
|
|
||||||
|
class MallocInfoHandler final : public HttpHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DECLARE_PTR_TYPEDEFS(MallocInfoHandler);
|
||||||
|
|
||||||
|
bool HandleRequest(
|
||||||
|
AsioTlsStream& stream,
|
||||||
|
const ApiUser::Ptr& user,
|
||||||
|
boost::beast::http::request<boost::beast::http::string_body>& request,
|
||||||
|
const Url::Ptr& url,
|
||||||
|
boost::beast::http::response<boost::beast::http::string_body>& response,
|
||||||
|
const Dictionary::Ptr& params,
|
||||||
|
boost::asio::yield_context& yc,
|
||||||
|
HttpServerConnection& server
|
||||||
|
) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue