agent/native/libcommon/code/Diagnostics.cpp (70 lines of code) (raw):
#include "Diagnostics.h"
#include <sys/types.h>
#include <unistd.h>
#include <chrono>
#include <fstream>
#include <sstream>
#include <iomanip>
namespace elasticapm::utils {
namespace detail {
static constexpr int separatorWidth = 60;
static constexpr char separator = '=';
}
static void getProcessDiags(std::ostream &out, std::string_view name) {
out << std::setfill(detail::separator) << std::setw(detail::separatorWidth) << detail::separator << std::endl;
out << "Process " << name << ":" << std::endl;
out << std::setfill(detail::separator) << std::setw(detail::separatorWidth) << detail::separator << std::endl;
try {
std::stringstream mapsname;
mapsname << "/proc/self/" << name;
std::ifstream maps;
maps.exceptions(std::ios_base::failbit);
maps.open(mapsname.str());
out << maps.rdbuf();
maps.close();
} catch (std::exception const &e) {
out << "Unable to get process " << name << ": " << e.what() << std::endl;
}
}
static void getDiagnosticInformation(std::ostream &out, elasticapm::php::PhpBridgeInterface const &bridge) {
out << std::setfill(detail::separator) << std::setw(detail::separatorWidth) << detail::separator << std::endl;
out << "Elastic APM PHP agent diagnostics:" << std::endl;
out << std::setfill(detail::separator) << std::setw(detail::separatorWidth) << detail::separator << std::endl;
std::time_t time = std::time({});
char timeString[std::size("yyyy-mm-ddThh:mm:ssZ")];
std::strftime(std::data(timeString), std::size(timeString), "%FT%TZ", std::gmtime(&time));
out << "Time: " << timeString << " UTC (" << std::chrono::milliseconds(time).count() << ')' << std::endl;
out << "PID: " << getpid() << std::endl;
out << "PPID: " << getppid() << std::endl;
out << "UID: " << getuid() << std::endl;
auto extensions = bridge.getExtensionList();
if (extensions.size() > 0) {
out << std::setfill(detail::separator) << std::setw(detail::separatorWidth) << detail::separator << std::endl;
out << "Loaded extensions:" << std::endl;
out << std::setfill(detail::separator) << std::setw(detail::separatorWidth) << detail::separator << std::endl;
for (auto const &extension : extensions) {
out << extension.name << " " << extension.version << std::endl;
}
}
out << std::setfill(detail::separator) << std::setw(detail::separatorWidth) << detail::separator << std::endl << std::endl;
out << "phpinfo() output:" << std::endl;
out << std::setfill(detail::separator) << std::setw(detail::separatorWidth) << detail::separator << std::endl;
out << bridge.getPhpInfo() << std::endl;
getProcessDiags(out, "maps");
getProcessDiags(out, "smaps_rollup");
getProcessDiags(out, "status");
getProcessDiags(out, "limits");
getProcessDiags(out, "cgroup");
getProcessDiags(out, "cmdline");
getProcessDiags(out, "mountinfo");
getProcessDiags(out, "mounts");
getProcessDiags(out, "mountstats");
getProcessDiags(out, "stat");
}
void storeDiagnosticInformation(std::string_view outputFileName, elasticapm::php::PhpBridgeInterface const &bridge) {
std::ofstream out;
out.exceptions(std::ios_base::failbit);
out.open(outputFileName.data());
getDiagnosticInformation(out, bridge);
}
}