Skip to content

Commit

Permalink
feat: observe api c++ bindings / improve observe api c bindings (#165)
Browse files Browse the repository at this point in the history
* feat: improve observe api c bindings

* namespace imports and give them `n` suffix to signify length param
* use stronger typing on imports to type issues at compile time
* rename observe_api_metric to observe_api_statsd
* add observe_api_metric taking a format param
* add observe_api_statsd_n
* rename observe_api_write_log to observe_api_log for consistency

* feat: add span tags to observe api c bindings

* feat: convert observe_api to single header library

* feat: start c++ observe api bindings

* feat(c++ observe api): Span class

* docs: add c and c++ header only library usage info
  • Loading branch information
G4Vi authored Jul 22, 2024
1 parent 4f1734a commit 2949c12
Show file tree
Hide file tree
Showing 11 changed files with 249 additions and 46 deletions.
6 changes: 4 additions & 2 deletions observe-api/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@ WASICXX?=$(WASI_SDK_PATH)/bin/clang++ --sysroot=${WASI_SDK_PATH}/share/wasi-sysr
build:
@cd test/rust && cargo build --target=wasm32-wasi && cd ../..
@cp test/rust/target/wasm32-wasi/debug/rust_guest.wasm test/rust_guest.wasm
$(WASICC) -o test/c_guest.wasm test/c/main.c c/observe_api.c
$(WASICXX) -o test/cxx_guest.wasm -x c++ test/c/main.c c/observe_api.c
$(WASICC) -o test/c_guest.wasm -I c test/c/main.c
$(WASICXX) -o test/cxx_guest.wasm -I c -x c++ test/c/main.c
$(WASICXX) -o test/cxx_guest_2.wasm -fno-exceptions -I c test/c/main.cpp
$(WASICXX) -o test/cxx_guest_3.wasm -fno-exceptions -I c test/c/main2.cpp
37 changes: 35 additions & 2 deletions observe-api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,41 @@ Ideally, you will not call this API layer directly but instead use language spec

We currently provide these language bindings to this API:

* [rust](rust/) -- [example](test/rust/src/main.rs)
* [c](c/) -- [example](test/c/main.c)
### [rust](rust/)

* [example](test/rust/src/main.rs)


### [c and c++](c/)

Both the C and C++ bindings are implemented as header-only libraries. To use the C bindings,
in __ONE__ source file:

```c
#define OBSERVE_API_IMPLEMENTATION
#include "observe_api.h"
```

In other source files, just `#include "observe_api.h"`

* [example](test/c/main.c)

To use the C++ bindings, instead, in __ONE__ source file:

```c++
#define OBSERVE_API_IMPLEMENTATION
#define OBSERVE_API_CPP_IMPLEMENTATION
#include "observe_api.hpp"
```

In other source files, just `#include "observe_api.hpp"`

__NOTE:__ `observe_api.hpp` `#include`s `observe_api.h`

* [functional example](test/c/main.cpp)
* [OO example](test/c/main2.cpp)

### Other

More languages will come soon as well as tools built on top of these bindings. If you are planning on building your own tooling we suggest using or contributing one of these language specific bindings.

26 changes: 0 additions & 26 deletions observe-api/c/observe_api.c

This file was deleted.

107 changes: 92 additions & 15 deletions observe-api/c/observe_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,111 @@

#define IMPORT(a, b) __attribute__((import_module(a), import_name(b)))

enum DO_LOG_LEVEL {
DO_LL_ERROR = 1,
DO_LL_WARN = 2,
DO_LL_INFO = 3,
DO_LL_DEBUG = 4,
DO_LL_TRACE = 5
};

enum DO_METRIC_FMT { DO_MF_STATSD = 1 };

IMPORT("dylibso:observe/api", "metric")
extern void _metric(uint32_t, uint32_t, uint32_t);
extern void observe_api_metric_n(enum DO_METRIC_FMT format, const char *metric,
size_t metric_length);
IMPORT("dylibso:observe/api", "log")
extern void _log(uint32_t, uint32_t, uint32_t);
extern void observe_api_log_n(enum DO_LOG_LEVEL level, const char *message,
size_t message_length);
IMPORT("dylibso:observe/api", "span-enter")
extern void _span_enter(uint32_t, uint32_t);
extern void observe_api_span_enter_n(const char *name, size_t name_length);
IMPORT("dylibso:observe/api", "span-exit")
extern void _span_exit(void);

enum DO_LOG_LEVEL {
DO_LL_ERROR = 0,
DO_LL_WARN = 1,
DO_LL_INFO = 2,
DO_LL_DEBUG = 3,
DO_LL_TRACE = 4
};
extern void observe_api_span_exit(void);
IMPORT("dylibso:observe/api", "span-tags")
extern void observe_api_span_tags_n(const char *tags, size_t tags_length);

#ifdef __cplusplus
extern "C" {
#endif

void observe_api_span_enter(const char *name);
void observe_api_span_exit(void);
void observe_api_metric(const char *metric);
void observe_api_write_log(const enum DO_LOG_LEVEL level, const char *msg);
void observe_api_metric(enum DO_METRIC_FMT format, const char *message);
void observe_api_statsd_n(const char *metric, const size_t metric_length);
void observe_api_statsd(const char *metric);
void observe_api_log(const enum DO_LOG_LEVEL level, const char *msg);
void observe_api_span_tags(const char *tags);
void observe_api_span_tags_from_array(const char *const tags[],
size_t num_tags);

#ifdef __cplusplus
}
#endif

#endif // OBSERVE_API_H

// avoid greying out the implementation section
#if defined(Q_CREATOR_RUN) || defined(__INTELLISENSE__) || \
defined(_CDT_PARSER__)
#define OBSERVE_API_IMPLEMENTATION
#endif

#ifdef OBSERVE_API_IMPLEMENTATION
#ifndef OBSERVE_API_C
#define OBSERVE_API_C

#include <stdint.h>
#include <stdlib.h>
#include <string.h>

void observe_api_span_enter(const char *name) {
const size_t name_length = strlen(name);
observe_api_span_enter_n(name, name_length);
}

void observe_api_metric(enum DO_METRIC_FMT format, const char *metric) {
const size_t metric_length = strlen(metric);
observe_api_metric_n(format, metric, metric_length);
}

void observe_api_statsd_n(const char *metric, const size_t metric_length) {
observe_api_metric_n(DO_MF_STATSD, metric, metric_length);
}

void observe_api_statsd(const char *metric) {
observe_api_metric(DO_MF_STATSD, metric);
}

void observe_api_log(const enum DO_LOG_LEVEL level, const char *msg) {
const size_t msg_length = strlen(msg);
observe_api_log_n(level, msg, msg_length);
}

void observe_api_span_tags(const char *tags) {
const size_t tags_length = strlen(tags);
observe_api_span_tags_n(tags, tags_length);
}

void observe_api_span_tags_from_array(const char *const tags[],
size_t num_tags) {
char *tags_buf = 0;
size_t tags_buf_size = 0;
for (size_t i = 0; i < num_tags; i++) {
size_t new_tag_length = strlen(tags[i]);
size_t new_tags_buf_size = tags_buf_size + new_tag_length + 1;
char *new_tags_buf = (char *)realloc(tags_buf, new_tags_buf_size);
if (!new_tags_buf) {
break;
}
memcpy(new_tags_buf + tags_buf_size, tags[i], new_tag_length);
new_tags_buf[new_tags_buf_size - 1] = ',';
tags_buf = new_tags_buf;
tags_buf_size = new_tags_buf_size;
}
if (tags_buf_size > 0) {
observe_api_span_tags_n(tags_buf, tags_buf_size - 1);
free(tags_buf);
}
}

#endif // OBSERVE_API_C
#endif // OBSERVE_API_IMPLEMENTATION
88 changes: 88 additions & 0 deletions observe-api/c/observe_api.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#ifndef OBSERVE_API_HPP
#define OBSERVE_API_HPP

#include "observe_api.h"
#include <string>
#include <string_view>
#include <vector>

namespace observe_api {
void span_enter(std::string_view name);
void span_exit();
void metric(enum DO_METRIC_FMT format, std::string_view mtc);
void log(enum DO_LOG_LEVEL level, std::string_view message);
void span_tags(std::string_view tags);
void statsd(std::string_view mtc);
void span_tags(std::vector<std::string> &tags);

class Span {
public:
Span(std::string_view name) { span_enter(name); }
~Span() { span_exit(); }
void metric(enum DO_METRIC_FMT format, std::string_view mtc) {
observe_api::metric(format, mtc);
}
void tags(std::string_view tags) { span_tags(tags); }
void statsd(std::string_view mtc) { observe_api::statsd(mtc); }
void tags(std::vector<std::string> &tags) { span_tags(tags); }
};
}; // namespace observe_api

#endif // OBSERVE_API_HPP

// avoid greying out the implementation section
#if defined(Q_CREATOR_RUN) || defined(__INTELLISENSE__) || \
defined(_CDT_PARSER__)
#define OBSERVE_API_CPP_IMPLEMENTATION
#endif

#ifdef OBSERVE_API_CPP_IMPLEMENTATION
#ifndef OBSERVE_API_CPP
#define OBSERVE_API_CPP

#include "observe_api.h"
#include <iterator>
#include <sstream>
#include <string>
#include <string_view>
#include <vector>

namespace observe_api {

void span_enter(std::string_view name) {
observe_api_span_enter_n(name.data(), name.size());
}

void span_exit() { observe_api_span_exit(); }

void metric(enum DO_METRIC_FMT format, std::string_view mtc) {
observe_api_metric_n(format, mtc.data(), mtc.size());
}

void log(enum DO_LOG_LEVEL level, std::string_view message) {
observe_api_log_n(level, message.data(), message.size());
}

void span_tags(std::string_view tags) {
observe_api_span_tags_n(tags.data(), tags.size());
}

void statsd(std::string_view mtc) {
observe_api_statsd_n(mtc.data(), mtc.size());
}

void span_tags(std::vector<std::string> &tags) {
const char *delim = ",";
std::ostringstream imploded;
std::copy(tags.begin(), tags.end(),
std::ostream_iterator<std::string>(imploded, delim));
std::string str = imploded.str();
if (str.size() > 0) {
observe_api_span_tags_n(str.data(), str.size() - 1);
}
}

}; // namespace observe_api

#endif // OBSERVE_API_CPP
#endif // OBSERVE_API_CPP_IMPLEMENTATION
8 changes: 7 additions & 1 deletion observe-api/test/c/main.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
#include "../../c/observe_api.h"
#define OBSERVE_API_IMPLEMENTATION
#include "observe_api.h"
#include <stdio.h>
#include <stdlib.h>

void run() {
observe_api_span_enter("printf");
observe_api_statsd("ok:aaaaa");
observe_api_log(DO_LL_INFO, "bbbbb");
observe_api_span_tags("abbc:def,(another:tag");
const char *const tags[] = {"taga:one", "tagb:two"};
observe_api_span_tags_from_array(tags, sizeof(tags) / sizeof(tags[0]));
printf("Hello from Wasm!\n");
observe_api_span_exit();
}
Expand Down
23 changes: 23 additions & 0 deletions observe-api/test/c/main2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#define OBSERVE_API_IMPLEMENTATION
#define OBSERVE_API_CPP_IMPLEMENTATION
#include "observe_api.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>

void run() {
auto span = observe_api::Span("printf");
span.statsd("ok:aaaaa");
observe_api::log(DO_LL_INFO, "bbbbb");
span.tags("abbc:def,(another:tag");
std::vector<std::string> tags = {"taga:one", "tagb:two"};
span.tags(tags);
printf("Hello from Wasm!\n");
}

int main(int argc, char *argv[]) {
auto span = observe_api::Span("run");
run();
return 0;
}
Binary file modified observe-api/test/c_guest.wasm
Binary file not shown.
Binary file modified observe-api/test/cxx_guest.wasm
Binary file not shown.
Binary file added observe-api/test/cxx_guest_2.wasm
Binary file not shown.
Binary file added observe-api/test/cxx_guest_3.wasm
Binary file not shown.

0 comments on commit 2949c12

Please sign in to comment.