prod/native/libcommon/code/Diagnostics.cpp (70 lines of code) (raw):
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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 Distribution for OpenTelemetry PHP 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);
}
}