berthubert / simplomon Goto Github PK
View Code? Open in Web Editor NEWVery simple monitoring system with a single configuration file
License: MIT License
Very simple monitoring system with a single configuration file
License: MIT License
I'd like to see simplomon being able to inform me via notifyer that it's alive, and since ping
checks other servers, maybe pong
(inspired from Ansible's ping
which reponds with pong
) could do so with a configurable interval, e.g. 3600 seconds.
Please add a ping test that allows:
This is to test firewall configurations (making sure things that shouldn't work, aren't working, and the inverse).
I'm running my own ntfy instance which is password protected via HTTP Basic Authentication (see https://docs.ntfy.sh/publish/#authentication). It would be great if you could add params for the url and authentication so one can use private ntfy instances.
As a service owner, you might know a whole bunch of IP addresses that DNS could hand out automatically.
We have infra to explicitly test your URL on a provided set of IP addresses. Hook that up.
On Ubuntu 20.04, meson compile -C build/
fails in testrunner
on 3 separate files.
As instructed, I'm using meson
from pip
, because meson
on Ubuntu 20.04 has version 0.53.2
$ git lg | head -n 1
* b8b4ecc - (HEAD -> main, origin/main, origin/HEAD) remove prometheus command for now to fix build (5 days ago) <bert hubert>
$ python3 -m venv venv
$ source venv/bin/activate
(venv) $ pip3 install meson ninja
(venv) $ meson --version
1.4.0
(venv) $ ninja --version
1.11.1.git.kitware.jobserver-1
(venv) $ meson setup build
[..]
simplomon undefined
Subprojects
cpp-httplib : YES 3 warnings
curl : YES 1 warnings
doctest : YES
fmt : YES
nlohmann_json: YES
simplesockets: YES
sqlitewriter : YES
Found ninja-1.11.1.git.kitware.jobserver-1 at /home/gerdriaan/scm/simplomon/venv/bin/ninja
(venv) $ meson compile -C build/ | tee -a /tmp/simplomon-compilelog
[..]
[175/214] Compiling C++ object subprojects/sqlitewriter/demo.p/demo.cc.o
[176/214] Compiling C++ object subprojects/simplesockets/testrunner.p/sclasses.cc.o
[177/214] Compiling C++ object subprojects/sqlitewriter/libsqlitewriter.a.p/jsonhelper.cc.o
[178/214] Compiling C++ object subprojects/sqlitewriter/demo.p/jsonhelper.cc.o
[179/214] Compiling C++ object subprojects/simplesockets/testrunner.p/swrappers.cc.o
[180/214] Compiling C++ object subprojects/sqlitewriter/testrunner.p/jsonhelper.cc.o
[181/214] Compiling C++ object subprojects/sqlitewriter/testrunner.p/testrunner.cc.o
ninja: build stopped: subcommand failed.
INFO: autodetecting backend as ninja
INFO: calculating backend command to run: /home/gerdriaan/scm/simplomon/venv/bin/ninja -C /home/gerdriaan/scm/simplomon/build
(venv) $
Excerpt from one error:
[172/214] Compiling C++ object subprojects/sqlitewriter/testrunner.p/sqlwriter.cc.o
FAILED: subprojects/sqlitewriter/testrunner.p/sqlwriter.cc.o
c++ -Isubprojects/sqlitewriter/testrunner.p -Isubprojects/sqlitewriter -I../subprojects/sqlitewriter -I../subprojects/nlohmann_json-3.11.2/single_include -fdiagnostics-color=always -D_GLIBCXX_ASSERTIONS=1 -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -std=c++17 -O0 -g -pthread -MD -MQ subprojects/sqlitewriter/testrunner.p/sqlwriter.cc.o -MF subprojects/sqlitewriter/testrunner.p/sqlwriter.cc.o.d -o subprojects/sqlitewriter/testrunner.p/sqlwriter.cc.o -c ../subprojects/sqlitewriter/sqlwriter.cc
../subprojects/sqlitewriter/sqlwriter.cc: In member function ‘void MiniSQLite::execPrep(const string&, std::vector<std::unordered_map<std::__cxx11::basic_string<char>, std::variant<double, long int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<unsigned char, std::allocator<unsigned char> >, std::nullptr_t> > >*)’:
../subprojects/sqlitewriter/sqlwriter.cc:134:94: error: no match for ‘operator=’ (operand types are ‘std::unordered_map<std::__cxx11::basic_string<char>, std::variant<double, long int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<unsigned char, std::allocator<unsigned char> >, std::nullptr_t> >::mapped_type’ {aka ‘std::variant<double, long int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<unsigned char, std::allocator<unsigned char> >, std::nullptr_t>’} and ‘sqlite3_int64’ {aka ‘long long int’})
134 | row[sqlite3_column_name(d_stmts[table], n)]= sqlite3_column_int64(d_stmts[table], n);
| ^
In file included from ../subprojects/sqlitewriter/sqlwriter.hh:5,
from ../subprojects/sqlitewriter/sqlwriter.cc:1:
/usr/include/c++/9/variant:1299:16: note: candidate: ‘std::variant<_Types>& std::variant<_Types>::operator=(const std::variant<_Types>&) [with _Types = {double, long int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<unsigned char, std::allocator<unsigned char> >, std::nullptr_t}]’
1299 | variant& operator=(const variant&) = default;
| ^~~~~~~~
/usr/include/c++/9/variant:1299:26: note: no known conversion for argument 1 from ‘sqlite3_int64’ {aka ‘long long int’} to ‘const std::variant<double, long int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<unsigned char, std::allocator<unsigned char> >, std::nullptr_t>&’
1299 | variant& operator=(const variant&) = default;
| ^~~~~~~~~~~~~~
/usr/include/c++/9/variant:1300:16: note: candidate: ‘std::variant<_Types>& std::variant<_Types>::operator=(std::variant<_Types>&&) [with _Types = {double, long int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<unsigned char, std::allocator<unsigned char> >, std::nullptr_t}]’
1300 | variant& operator=(variant&&) = default;
| ^~~~~~~~
/usr/include/c++/9/variant:1300:26: note: no known conversion for argument 1 from ‘sqlite3_int64’ {aka ‘long long int’} to ‘std::variant<double, long int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<unsigned char, std::allocator<unsigned char> >, std::nullptr_t>&&’
1300 | variant& operator=(variant&&) = default;
| ^~~~~~~~~
/usr/include/c++/9/variant:1362:2: note: candidate: ‘template<class _Tp> std::enable_if_t<((__exactly_once<std::variant<_Types>::__accepted_type<_Tp&&, typename std::enable_if<__not_self<_Tp&&>, void>::type> > && is_constructible_v<std::variant<_Types>::__accepted_type<_Tp&&, typename std::enable_if<__not_self<_Tp&&>, void>::type>, _Tp>) && is_assignable_v<std::variant<_Types>::__accepted_type<_Tp&&, typename std::enable_if<__not_self<_Tp&&>, void>::type>&, _Tp>), std::variant<_Types>&> std::variant<_Types>::operator=(_Tp&&) [with _Tp = _Tp; _Types = {double, long int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<unsigned char, std::allocator<unsigned char> >, std::nullptr_t}]’
1362 | operator=(_Tp&& __rhs)
| ^~~~~~~~
/usr/include/c++/9/variant:1362:2: note: template argument deduction/substitution failed:
/usr/include/c++/9/variant: In substitution of ‘template<class ... _Types> template<class _Tp, class> using __accepted_type = std::variant<_Types>::__to_type<__accepted_index<_Tp> > [with _Tp = long long int&&; <template-parameter-2-2> = std::enable_if<true, void>::type; _Types = {double, long int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<unsigned char, std::allocator<unsigned char> >, std::nullptr_t}]’:
/usr/include/c++/9/variant:1358:14: required by substitution of ‘template<class _Tp> std::enable_if_t<((__exactly_once<std::variant<double, long int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<unsigned char, std::allocator<unsigned char> >, std::nullptr_t>::__accepted_type<_Tp&&, typename std::enable_if<__not_self<_Tp&&>, void>::type> > && is_constructible_v<std::variant<double, long int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<unsigned char, std::allocator<unsigned char> >, std::nullptr_t>::__accepted_type<_Tp&&, typename std::enable_if<__not_self<_Tp&&>, void>::type>, _Tp>) && is_assignable_v<std::variant<double, long int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<unsigned char, std::allocator<unsigned char> >, std::nullptr_t>::__accepted_type<_Tp&&, typename std::enable_if<__not_self<_Tp&&>, void>::type>&, _Tp>), std::variant<double, long int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<unsigned char, std::allocator<unsigned char> >, std::nullptr_t>&> std::variant<double, long int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<unsigned char, std::allocator<unsigned char> >, std::nullptr_t>::operator=<_Tp>(_Tp&&) [with _Tp = long long int]’
../subprojects/sqlitewriter/sqlwriter.cc:134:94: required from here
/usr/include/c++/9/variant:1276:8: error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
1276 | using __accepted_type = __to_type<__accepted_index<_Tp>>;
| ^~~~~~~~~~~~~~~
Two other failures, but full log omitted for brevity:
[173/214] Compiling C++ object subprojects/sqlitewriter/libsqlitewriter.a.p/sqlwriter.cc.o
FAILED: subprojects/sqlitewriter/libsqlitewriter.a.p/sqlwriter.cc.o
c++ -Isubprojects/sqlitewriter/libsqlitewriter.a.p -Isubprojects/sqlitewriter -I../subprojects/sqlitewriter -I../subprojects/nlohmann_json-3.11.2/single_include -fdiagnostics-color=always -D_GLIBCXX_ASSERTIONS=1 -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -std=c++17 -O0 -g -fPIC -pthread -MD -MQ subprojects/sqlitewriter/libsqlitewriter.a.p/sqlwriter.cc.o -MF subprojects/sqlitewriter/libsqlitewriter.a.p/sqlwriter.cc.o.d -o subprojects/sqlitewriter/libsqlitewriter.a.p/sqlwriter.cc.o -c ../subprojects/sqlitewriter/sqlwriter.cc
../subprojects/sqlitewriter/sqlwriter.cc: In member function ‘void MiniSQLite::execPrep(const string&, std::vector<std::unordered_map<std::__cxx11::basic_string<char>, std::variant<double, long int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<unsigned char, std::allocator<unsigned char> >, std::nullptr_t> > >*)’:
../subprojects/sqlitewriter/sqlwriter.cc:134:94: error: no match for ‘operator=’ (operand types are ‘std::unordered_map<std::__cxx11::basic_string<char>, std::variant<double, long int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<unsigned char, std::allocator<unsigned char> >, std::nullptr_t> >::mapped_type’ {aka ‘std::variant<double, long int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<unsigned char, std::allocator<unsigned char> >, std::nullptr_t>’} and ‘sqlite3_int64’ {aka ‘long long int’})
134 | row[sqlite3_column_name(d_stmts[table], n)]= sqlite3_column_int64(d_stmts[table], n);
| ^
[174/214] Compiling C++ object subprojects/sqlitewriter/demo.p/sqlwriter.cc.o
FAILED: subprojects/sqlitewriter/demo.p/sqlwriter.cc.o
c++ -Isubprojects/sqlitewriter/demo.p -Isubprojects/sqlitewriter -I../subprojects/sqlitewriter -I../subprojects/nlohmann_json-3.11.2/single_include -fdiagnostics-color=always -D_GLIBCXX_ASSERTIONS=1 -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -std=c++17 -O0 -g -pthread -MD -MQ subprojects/sqlitewriter/demo.p/sqlwriter.cc.o -MF subprojects/sqlitewriter/demo.p/sqlwriter.cc.o.d -o subprojects/sqlitewriter/demo.p/sqlwriter.cc.o -c ../subprojects/sqlitewriter/sqlwriter.cc
../subprojects/sqlitewriter/sqlwriter.cc: In member function ‘void MiniSQLite::execPrep(const string&, std::vector<std::unordered_map<std::__cxx11::basic_string<char>, std::variant<double, long int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<unsigned char, std::allocator<unsigned char> >, std::nullptr_t> > >*)’:
../subprojects/sqlitewriter/sqlwriter.cc:134:94: error: no match for ‘operator=’ (operand types are ‘std::unordered_map<std::__cxx11::basic_string<char>, std::variant<double, long int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<unsigned char, std::allocator<unsigned char> >, std::nullptr_t> >::mapped_type’ {aka ‘std::variant<double, long int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<unsigned char, std::allocator<unsigned char> >, std::nullptr_t>’} and ‘sqlite3_int64’ {aka ‘long long int’})
134 | row[sqlite3_column_name(d_stmts[table], n)]= sqlite3_column_int64(d_stmts[table], n);
| ^
This looks similar to #5, except it's on Linux.
Currently installed dependency versions:
$ apt search '^(python3-pip|pkg-config|libnghttp2-dev|libssl-dev|liblua5.3-dev)' 2>/dev/null | grep -ie 'upgradable' -e 'install'
liblua5.3-dev/focal,now 5.3.3-1.1ubuntu2 amd64 [installed]
libnghttp2-dev/focal-updates,focal-security,now 1.40.0-1ubuntu0.2 amd64 [installed]
libssl-dev/focal-updates,focal-security 1.1.1f-1ubuntu2.22 amd64 [upgradable from: 1.1.1f-1ubuntu2.19]
pkg-config/focal,now 0.29.1-0ubuntu4 amd64 [installed,automatic]
python3-pip/focal-updates,focal-security 20.0.2-5ubuntu1.10 all [upgradable from: 20.0.2-5ubuntu1.9]
As SMTP STARTTLS checks are on the roadmap, and there is infrastructure to query DNS, maybe it makes sense to add the option to validate that the certificate offered in SMTP STARTTLS matches the DANE records to the roadmap as well.
To reduce implementation effort, maybe limit it to the sane subset of DANE, so options 3 / 1 / 1 as advised in https://github.com/internetstandards/toolbox-wiki/blob/main/DANE-for-SMTP-how-to.md#publishing-dane-records
The recently added HTTP endpoint as well as the HTTP redirection check are vulnerable to the same issue as Trifecta when it comes to accepting crafted requests and responses with a Brotli Content-Encoding
, a feature that is enabled by default if simplomon is compiled on a machine that has Brotli headers present.
Again, taking an example file from here and bunzipping it, we have a small Brotli file that uncompresses to a large amount of data. When we send this file, either as part of a request to the status endpoint or as a response to a redir check, simplomon will attempt to allocate enough memory to hold the result, which exceeds the amount of available memory. The exact behavior is somewhat system-dependent, but on my machine this triggers the OOM killer, which then kills the simplomon process.
% /tmp › curl -v -H 'Content-Encoding: br' --data-binary @10GB.html.br http://127.0.0.1:8080/health
* Trying 127.0.0.1:8080...
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> POST /health HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/8.0.1
> Accept: */*
> Content-Encoding: br
> Content-Length: 27036
> Content-Type: application/x-www-form-urlencoded
>
* Recv failure: Connection reset by peer
* Closing connection 0
curl: (56) Recv failure: Connection reset by peer
For the redir check, the following configuration allocates 10GB of memory:
httpredir{fromUrl="http://demo.52-7-242-28.nip.io", toUrl="http://example.com/"}
A possible mitigation would be the same as on the Trifecta side, that is, to disable Brotli support entirely. For simplomon, it seems unlikely that either requests or responses would benefit from compression at all.
In general, it might be sensible to document (perhaps in the README) whether it is expected that simplomon instances be available from the internet, and if not, perhaps bind to the loopback interface instead of 0.0.0.0.
Compilation fails on FreeBSD in netmon.cc
[1/2] Compiling C++ object simplomon.p/netmon.cc.o
FAILED: simplomon.p/netmon.cc.o
ccache c++ -Isimplomon.p -I. -I.. -Isubprojects/cpp-httplib-0.13.1 -I../subprojects/cpp-httplib-0.13.1 -Isubprojects/simplesockets -I../subprojects/simplesockets -I/usr/local/include -I/usr/local/include/lua53 -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -std=c++20 -O0 -g -pthread -DCPPHTTPLIB_OPENSSL_SUPPORT -DCPPHTTPLIB_ZLIB_SUPPORT -DCPPHTTPLIB_BROTLI_SUPPORT -MD -MQ simplomon.p/netmon.cc.o -MF simplomon.p/netmon.cc.o.d -o simplomon.p/netmon.cc.o -c ../netmon.cc
In file included from ../netmon.cc:6:
In file included from ../simplomon.hh:6:
In file included from ../notifiers.hh:3:
../sol/sol.hpp:14541:32: warning: unknown warning group '-Wmaybe-uninitialized', ignored [-Wunknown-warning-option]
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
^
../sol/sol.hpp:17294:32: warning: unknown warning group '-Wmaybe-uninitialized', ignored [-Wunknown-warning-option]
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
^
In file included from ../netmon.cc:10:
/usr/include/netinet/ip_icmp.h:110:14: error: field has incomplete type 'struct ip'
struct ip idi_ip;
^
/usr/include/netinet/ip_icmp.h:110:11: note: forward declaration of 'ip'
struct ip idi_ip;
^
../netmon.cc:220:11: error: no member named 'type' in 'icmphdr'
p.hdr.type = ICMP_ECHO;
~~~~~ ^
../netmon.cc:221:11: error: no member named 'un' in 'icmphdr'
p.hdr.un.echo.id = id;
~~~~~ ^
../netmon.cc:222:11: error: no member named 'un' in 'icmphdr'
p.hdr.un.echo.sequence = seq;
~~~~~ ^
../netmon.cc:229:11: error: no member named 'checksum' in 'icmphdr'
p.hdr.checksum = 0;
~~~~~ ^
../netmon.cc:230:11: error: no member named 'checksum' in 'icmphdr'
p.hdr.checksum = internetchecksum(&p, sizeof(p));
~~~~~ ^
../netmon.cc:251:73: error: member access into incomplete type 'struct iphdr'
struct icmphdr* icmp = (struct icmphdr*) ((char*)packet.c_str() + ip->ihl*4);
^
../netmon.cc:250:12: note: forward declaration of 'iphdr'
struct iphdr *ip = (iphdr*)packet.c_str();
^
../netmon.cc:253:16: error: no member named 'un' in 'icmphdr'
id = icmp->un.echo.id;
~~~~ ^
../netmon.cc:254:17: error: no member named 'un' in 'icmphdr'
seq = icmp->un.echo.sequence;
~~~~ ^
../netmon.cc:256:31: error: member access into incomplete type 'struct iphdr'
payload = packet.substr(ip->ihl*4 + sizeof(icmp));
^
../netmon.cc:250:12: note: forward declaration of 'iphdr'
struct iphdr *ip = (iphdr*)packet.c_str();
^
2 warnings and 10 errors generated.
ninja: build stopped: subcommand failed.
Hi,
I'm not sure if this falls into an area you would be interested in for simplemon. I recently was looking for a lean way to monitor my SMTP VPS (vCPU, 1GB RAM). I mainly wanted to make sure I dont run out of (very limited) disk space and couldn't find anything really small. I ended up with very slimmed down netdata that is sending the data to another beefier server. But it's still the biggest process on the VPS. I don't need no graphs or CPU usage or whatever else netdata provides, just a notification if the disk space is over 85%.
I think setting up an SSH key and adding the check config should be doable in 5mins, so maybe it's a feature request you might consider. Thanks!
Using build b14b8d4
ninja: Entering directory `/home/roel/tools/simplomon/build'
[1/16] Compiling C++ object simplomon.p/minicurl.cc.o
../minicurl.cc: In member function ‘void MiniCurl::setupURL(const string&, const ComboAddress*, const ComboAddress*)’:
../minicurl.cc:122:9: warning: unused variable ‘ret’ [-Wunused-variable]
122 | int ret = curl_easy_setopt(d_curl, CURLOPT_INTERFACE, src->toString().c_str());
| ^~~
[5/16] Compiling C++ object testrunner.p/minicurl.cc.o
../minicurl.cc: In member function ‘void MiniCurl::setupURL(const string&, const ComboAddress*, const ComboAddress*)’:
../minicurl.cc:122:9: warning: unused variable ‘ret’ [-Wunused-variable]
122 | int ret = curl_easy_setopt(d_curl, CURLOPT_INTERFACE, src->toString().c_str());
| ^~~
[16/16] Linking target testrunner
Simplomon reports the following exception when it attempts to connect to my Postfix mail server:
Got an exception during check: Unexpected response from SMTP server: '503 5.5.1 Error: send HELO/EHLO first
I am willing to provide credentials to a test account if needed for troubleshooting.
Would be nice to see for every check when it created an alert, and for how long. Perhaps do some stats too.
I mentioned this recently on the Fediverse, and now as a reminder. What I'd like to see is for simplomon being able to verify whether a particular file is on the file system, and check preferable via a regexp I specify if a string is contained therein.
Regexp check can also be useful on, say, https
checks to determine whether a particular string or expression is contained in whatever the check responds with.
in my configuration I have stated https{url="https://mywebsite.com"}
When I get an alert (with Pushover) I get the alert:
https: [ipv4] Unable to retrieve URL 'https://mywebsite.com': SSL peer certificate or SSH remote key was not OK
In the (iPhone) Pushover app, the URL is a clickable link. When I click that link, the browser tries to open
https://snappass.leeuwen.net'
(including the extra ' at the end), which is not a valid URL.
use case:
As a simple example, dailyChime issues a new chime every day. This leads to a notification that the old chime is over. And then there is the new one. This is silly. We should have an identifier that says this is still the same alert, and that there is no need to announce that the old one was over.
This could happen with an explicit alert key perhaps.
Hello,
I'm trying to get this to compile on FreeBSD (having never used meson/C++/etc before) and have managed to get it to work if I add:
incdir = include_directories('/usr/local/include/doctest')
and modify the testrunner executable() to include the include_directories
executable('testrunner', 'testrunner.cc', 'notifiers.cc', 'minicurl.cc', 'dnsmon.cc', 'record-types.cc',
'dnsmessages.cc', 'dns-storage.cc', 'netmon.cc', 'luabridge.cc',
dependencies: [doctest_dep, curl_dep, json_dep, fmt_dep, cpphttplib, simplesockets_dep,
lua_dep],
include_directories: incdir)
Is this something that can be added in a portable way? Maybe something like:
if host_machine.system() in ['freebsd']
incdir = include_directories('/usr/local/include/doctest')
executable('testrunner', 'testrunner.cc', 'notifiers.cc', 'minicurl.cc', 'dnsmon.cc', 'record-types.cc', 'dnsmessages.cc', 'dns-storage.cc', 'netmon.cc', 'luabridge.cc',
dependencies: [doctest_dep, curl_dep, json_dep, fmt_dep, cpphttplib, simplesockets_dep, lua_dep],
include_directories: incdir)
else
executable('testrunner', 'testrunner.cc', 'notifiers.cc', 'minicurl.cc', 'dnsmon.cc', 'record-types.cc', 'dnsmessages.cc', 'dns-storage.cc', 'netmon.cc', 'luabridge.cc',
dependencies: [doctest_dep, curl_dep, json_dep, fmt_dep, cpphttplib, simplesockets_dep, lua_dep])
endif
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.