-
Notifications
You must be signed in to change notification settings - Fork 124
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
965 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright (c) 2016, Ilya Khaprov <[email protected]>. | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# OpenTelemetry Process Instrumentation | ||
|
||
NIF code is based on https://github.com/deadtrickster/prometheus_process_collector | ||
|
||
OpenTelemtry instrumentation with metrics of the current state of cpu, memory, file descriptor usage and native threads count as well as the process start and up times. Implements all process metrics from OpenTelemetry's semantic convertions and some more. | ||
|
||
- FreeBSD; | ||
- Linux - uses /proc; | ||
- MacOS X (expiremental). | ||
|
||
After installing, setup the desired metrics in your application behaviour before your | ||
top-level supervisor starts. Make sure the API and SDK applications are started before | ||
your application. | ||
|
||
```erlang | ||
opentelemetry_process_metrics:setup(), | ||
... | ||
``` | ||
|
||
Build | ||
----- | ||
|
||
$ rebar3 compile | ||
|
||
License | ||
----- | ||
|
||
FreeBSD-specific part uses copy-modified code from standard utils (limits and procstat) or standard API in some places. | ||
|
||
MIT |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
# Based on c_src.mk from erlang.mk by Loic Hoguin <[email protected]> | ||
|
||
CURDIR := $(shell pwd) | ||
BASEDIR := $(abspath $(CURDIR)/..) | ||
|
||
PROJECT ?= $(notdir $(BASEDIR)) | ||
PROJECT := $(strip $(PROJECT)) | ||
|
||
ERTS_INCLUDE_DIR ?= $(shell erl -noshell -eval "io:format(\"~s/erts-~s/include/\", [code:root_dir(), erlang:system_info(version)])." -s erlang halt) | ||
ERL_INTERFACE_INCLUDE_DIR ?= $(shell erl -noshell -eval "io:format(\"~s\", [code:lib_dir(erl_interface, include)])." -s erlang halt) | ||
ERL_INTERFACE_LIB_DIR ?= $(shell erl -noshell -eval "io:format(\"~s\", [code:lib_dir(erl_interface, lib)])." -s erlang halt) | ||
|
||
C_SRC_DIR = $(CURDIR) | ||
C_SRC_OUTPUT ?= $(CURDIR)/../priv/$(PROJECT).so | ||
MEMTEST_OUTPUT ?= $(CURDIR)/../_build/memory_test | ||
|
||
.PHONY: memory-test | ||
|
||
# System type and C compiler/flags. | ||
|
||
UNAME_SYS := $(shell uname -s) | ||
ifeq ($(UNAME_SYS), Darwin) | ||
CXX ?= c++ | ||
CXXFLAGS += -O3 -finline-functions | ||
LDFLAGS += -flat_namespace -undefined suppress | ||
PSOURCES = otel_process_info_macos.cc | ||
else ifeq ($(UNAME_SYS), FreeBSD) | ||
CXX ?= c++ | ||
CXXEFLAGS += -D__STANDALONE_TEST__ -std=c++11 -Wall | ||
CXXFLAGS += -O3 -finline-functions | ||
PSOURCES = otel_process_info_freebsd.cc | ||
else ifeq ($(UNAME_SYS), Linux) | ||
CXX ?= g++ | ||
CXXEFLAGS += -D__STANDALONE_TEST__ -std=c++11 -Wall | ||
CXXFLAGS += -O3 -finline-functions | ||
PSOURCES = otel_process_info_linux.cc | ||
endif | ||
|
||
SOURCES = otel_process_metrics_nif.cc $(PSOURCES) | ||
|
||
CXXFLAGS += -fPIC -I $(ERTS_INCLUDE_DIR) -I $(ERL_INTERFACE_INCLUDE_DIR) -std=c++11 -Wall | ||
LDLIBS += -L $(ERL_INTERFACE_LIB_DIR) -lei | ||
|
||
ifeq ($(UNAME_SYS), OpenBSD) | ||
LDLIBS += -lestdc++ | ||
else | ||
LDLIBS += -lstdc++ | ||
endif | ||
|
||
LDFLAGS += -shared | ||
|
||
# Verbosity. | ||
|
||
cpp_verbose_0 = @echo " CPP " $(?F); | ||
cpp_verbose = $(cpp_verbose_$(V)) | ||
|
||
link_verbose_0 = @echo " LD " $(@F); | ||
link_verbose = $(link_verbose_$(V)) | ||
|
||
OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) | ||
|
||
COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c | ||
|
||
$(C_SRC_OUTPUT): $(OBJECTS) | ||
@mkdir -p $(BASEDIR)/priv/ | ||
$(link_verbose) $(CC) $(OBJECTS) $(LDFLAGS) $(LDLIBS) -o $(C_SRC_OUTPUT) | ||
|
||
%.o: %.cc | ||
$(COMPILE_CPP) $(OUTPUT_OPTION) $< | ||
|
||
%.o: %.cpp | ||
$(COMPILE_CPP) $(OUTPUT_OPTION) $< | ||
|
||
memory-test: | ||
@mkdir -p $(BASEDIR)/_build/ | ||
$(CXX) $(CXXEFLAGS) $(LDLIBS) otel_process_info_mt.cc $(PSOURCES) -o $(MEMTEST_OUTPUT) | ||
valgrind --leak-check=full --error-exitcode=1 $(MEMTEST_OUTPUT) 2 | ||
|
||
clean: | ||
@rm -f $(C_SRC_OUTPUT) $(OBJECTS) |
12 changes: 12 additions & 0 deletions
12
instrumentation/opentelemetry_process/c_src/otel_exceptions.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
#pragma once | ||
|
||
#include <stdexcept> | ||
|
||
namespace Prometheus | ||
{ | ||
class ProcessInfoException : public std::runtime_error | ||
{ | ||
public: | ||
ProcessInfoException() : std::runtime_error("ProcessInfoException") {} | ||
}; | ||
} |
105 changes: 105 additions & 0 deletions
105
instrumentation/opentelemetry_process/c_src/otel_process_info.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
#pragma once | ||
|
||
#include <cstdint> | ||
#include <cstdio> | ||
#include <ctime> | ||
#include <unistd.h> | ||
|
||
#if defined(__FreeBSD__) || defined(__APPLE__) | ||
#include <sys/sysctl.h> | ||
#include <sys/user.h> | ||
#endif | ||
|
||
#ifdef __linux__ | ||
#include <dirent.h> | ||
#include <errno.h> | ||
#include <string.h> | ||
#include <sys/resource.h> | ||
#include <time.h> | ||
#endif | ||
|
||
#ifdef __APPLE__ | ||
#include <libproc.h> | ||
#include <sys/proc_info.h> | ||
#endif | ||
|
||
#include "otel_exceptions.h" | ||
|
||
#define UNUSED(x) (void)(x) | ||
|
||
namespace Prometheus | ||
{ | ||
class ProcessInfo | ||
{ | ||
private: | ||
static struct rlimit get_process_limit(int resource) | ||
{ | ||
struct rlimit rlp; | ||
if (getrlimit(resource, &rlp)) | ||
{ | ||
throw ProcessInfoException(); | ||
} | ||
|
||
return rlp; | ||
}; | ||
|
||
void set_rusage() | ||
{ | ||
struct rusage rusage; | ||
getrusage(RUSAGE_SELF, &rusage); | ||
utime_seconds = rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec / 1000000.00; | ||
stime_seconds = rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec / 1000000.00; | ||
max_rm_bytes = rusage.ru_maxrss * 1024; | ||
noio_pagefaults_total = rusage.ru_minflt; | ||
io_pagefaults_total = rusage.ru_majflt; | ||
swaps_total = rusage.ru_nswap; | ||
disk_reads_total = rusage.ru_inblock; | ||
disk_writes_total = rusage.ru_oublock; | ||
signals_delivered_total = rusage.ru_nsignals; | ||
voluntary_context_switches_total = rusage.ru_nvcsw; | ||
involuntary_context_switches_total = rusage.ru_nivcsw; | ||
}; | ||
|
||
void set_fds_limit() | ||
{ | ||
const auto &fds_rlimit = get_process_limit(RLIMIT_NOFILE); | ||
fds_limit = fds_rlimit.rlim_cur; | ||
}; | ||
|
||
int get_fds_total(); | ||
void set_proc_stat(); | ||
public: | ||
pid_t pid; | ||
time_t now; | ||
int fds_total; | ||
uintmax_t fds_limit; | ||
uintmax_t start_time_seconds; | ||
long uptime_seconds; | ||
int threads_total; | ||
unsigned long vm_bytes; | ||
unsigned long rm_bytes; | ||
double utime_seconds; | ||
double stime_seconds; | ||
long max_rm_bytes; | ||
long noio_pagefaults_total; | ||
long io_pagefaults_total; | ||
long swaps_total; | ||
long disk_reads_total; | ||
long disk_writes_total; | ||
long signals_delivered_total; | ||
long voluntary_context_switches_total; | ||
long involuntary_context_switches_total; | ||
|
||
ProcessInfo() | ||
{ | ||
pid = getpid(); | ||
|
||
fds_total = get_fds_total(); | ||
set_fds_limit(); | ||
set_rusage(); | ||
std::time(&now); | ||
|
||
set_proc_stat(); | ||
} | ||
}; | ||
} |
135 changes: 135 additions & 0 deletions
135
instrumentation/opentelemetry_process/c_src/otel_process_info_freebsd.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
#include "otel_process_info.h" | ||
#include <cstdio> | ||
#include <ctime> | ||
#include <memory> | ||
|
||
namespace Prometheus | ||
{ | ||
static long pagesize(void) | ||
{ | ||
uint pageSize; | ||
size_t len = sizeof(pageSize); | ||
if (sysctlbyname("vm.stats.vm.v_page_size", &pageSize, &len, NULL, 0) == -1) | ||
{ | ||
long spageSize = sysconf(_SC_PAGESIZE); | ||
if (spageSize == -1) | ||
{ | ||
throw ProcessInfoException(); | ||
} | ||
else | ||
{ | ||
return spageSize; | ||
} | ||
} | ||
else | ||
{ | ||
return pageSize; | ||
} | ||
} | ||
|
||
static std::unique_ptr<kinfo_proc> kinfo_getproc(pid_t pid) | ||
{ | ||
int mib[4]; | ||
size_t len; | ||
|
||
len = 0; | ||
mib[0] = CTL_KERN; | ||
mib[1] = KERN_PROC; | ||
mib[2] = KERN_PROC_PID; | ||
mib[3] = pid; | ||
if (sysctl(mib, nitems(mib), NULL, &len, NULL, 0) < 0) | ||
{ | ||
throw ProcessInfoException(); | ||
} | ||
std::unique_ptr<kinfo_proc> | ||
kipp {reinterpret_cast<kinfo_proc*>(new char[len])}; | ||
|
||
if (sysctl(mib, 4, kipp.get(), &len, NULL, 0) < 0) | ||
{ | ||
throw ProcessInfoException(); | ||
} | ||
if (len != sizeof(*kipp)) | ||
{ | ||
throw ProcessInfoException(); | ||
} | ||
if (kipp->ki_structsize != sizeof(*kipp)) | ||
{ | ||
throw ProcessInfoException(); | ||
} | ||
if (kipp->ki_pid != pid) | ||
{ | ||
throw ProcessInfoException(); | ||
} | ||
|
||
return kipp; | ||
} | ||
|
||
/* | ||
from https://github.com/freebsd/freebsd/blob/9e0a154b0fd5fa9010238ac9497ec59f84167c92/lib/libutil/kinfo_getfile.c#L22-L51 | ||
I don't need unpacked structs here, just count. Hope it won't break someday. | ||
*/ | ||
int ProcessInfo::get_fds_total() | ||
{ | ||
int mib[4]; | ||
int error; | ||
int count; | ||
size_t len; | ||
char *buf, *eb; | ||
struct kinfo_file *kf; | ||
|
||
// get size of all pids | ||
len = 0; | ||
mib[0] = CTL_KERN; | ||
mib[1] = KERN_PROC; | ||
mib[2] = KERN_PROC_FILEDESC; | ||
mib[3] = pid; | ||
|
||
error = sysctl(mib, nitems(mib), NULL, &len, NULL, 0); | ||
if (error) | ||
{ | ||
throw ProcessInfoException(); | ||
} | ||
|
||
// allocate buf for pids | ||
len = len * 4 / 3; | ||
buf = (char*)malloc(len); | ||
if (buf == NULL) | ||
{ | ||
throw ProcessInfoException(); | ||
} | ||
|
||
// fill buf with kinfo_files | ||
error = sysctl(mib, nitems(mib), buf, &len, NULL, 0); | ||
if (error) | ||
{ | ||
free(buf); | ||
throw ProcessInfoException(); | ||
} | ||
|
||
// count structs in the buf | ||
count = 0; | ||
eb = buf + len; | ||
while (buf < eb) | ||
{ | ||
kf = (struct kinfo_file *)(uintptr_t)buf; | ||
if (kf->kf_structsize == 0) | ||
break; | ||
buf += kf->kf_structsize; | ||
count++; | ||
} | ||
|
||
free(buf - len); | ||
return count; | ||
} | ||
|
||
void ProcessInfo::set_proc_stat() | ||
{ | ||
auto proc = kinfo_getproc(pid); | ||
|
||
start_time_seconds = proc->ki_start.tv_sec; | ||
uptime_seconds = now - proc->ki_start.tv_sec; | ||
threads_total = proc->ki_numthreads; | ||
vm_bytes = proc->ki_size; | ||
rm_bytes = proc->ki_rssize * pagesize(); | ||
} | ||
} |
Oops, something went wrong.