Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added glue go code #1

Merged
merged 7 commits into from
Jul 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions c_api.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Copyright 2019. Starry, Inc. All Rights Reserved.
//
// MIT License
//
// 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.
//
// Software written by Preston Carpenter <pcarpenter@starry.com>
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>

struct go_value {
enum {
TYPE_INT,
TYPE_UINT,
TYPE_FLOAT,
TYPE_BOOL,
TYPE_STRING,
} type_;
union {
int64_t int_;
uint64_t uint_;
double double_;
bool bool_;
char *string_;
} value;
};

struct tag {
char *key, *value;
};

struct field {
char *key;
struct go_value value;
};

static int64_t get_go_value_int(struct go_value go_value) {
assert(go_value.type_ == TYPE_INT);
return go_value.value.int_;
}

static uint64_t get_go_value_uint(struct go_value go_value) {
assert(go_value.type_ == TYPE_UINT);
return go_value.value.uint_;
}

static double get_go_value_double(struct go_value go_value) {
assert(go_value.type_ == TYPE_FLOAT);
return go_value.value.double_;
}

static bool get_go_value_bool(struct go_value go_value) {
assert(go_value.type_ == TYPE_BOOL);
return go_value.value.bool_;
}

static char *get_go_value_string(struct go_value go_value) {
assert(go_value.type_ == TYPE_STRING);
return go_value.value.string_;
}

// Gives a sample configuration for this plugin.
char *sample_config(void);

// Gives a description for what this plugin does.
char *description(void);

// Called by Go at a regular interval to collect data.
void gather(void);

extern void add_field(char *measurment,
struct tag *tags, int tags_size,
struct field *fields, int fields_size,
int64_t unix_sec, int64_t unix_nsec);

extern void add_gauge(char *measurment,
struct tag *tags, int tags_size,
struct field *fields, int fields_size,
int64_t unix_sec, int64_t unix_nsec);

extern void add_counter(char *measurment,
struct tag *tags, int tags_size,
struct field *fields, int fields_size,
int64_t unix_sec, int64_t unix_nsec);

extern void add_summary(char *measurment,
struct tag *tags, int tags_size,
struct field *fields, int fields_size,
int64_t unix_sec, int64_t unix_nsec);

extern void add_histogram(char *measurment,
struct tag *tags, int tags_size,
struct field *fields, int fields_size,
int64_t unix_sec, int64_t unix_nsec);
183 changes: 183 additions & 0 deletions lib.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
// Copyright 2019. Starry, Inc. All Rights Reserved.
//
// MIT License
//
// 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.
//
// Software written by Preston Carpenter <pcarpenter@starry.com>
package main

/*
#cgo CFLAGS: -g -Wall -Wpedantic -Werror -Wno-unused-function -Wno-unused-variable
#cgo LDFLAGS: -L. -l:plugin.a -ldl
#include "c_api.h"
*/
import "C"

import (
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/inputs"
"log"
"time"
"unsafe"
)

type RustPlugin struct{}

var Plugin telegraf.Input = &RustPlugin{}
var acc *telegraf.Accumulator = nil

func init() {
inputs.Add("rust_plugin", func() telegraf.Input { return &RustPlugin{} })
}

func (plugin *RustPlugin) SampleConfig() string {
return C.GoString(C.sample_config())
}

func (plugin *RustPlugin) Description() string {
return C.GoString(C.description())
}

func (plugin *RustPlugin) Gather(acc_ telegraf.Accumulator) error {
acc = &acc_
C.gather()
acc = nil
return nil
}

type add_func func(measurement string,
fields map[string]interface{},
tags map[string]string,
t ...time.Time)

func add_generic(measurement_ *C.char,
tags_ *C.struct_tag, tags_size C.int,
fields_ *C.struct_field, fields_size C.int,
unix_sec, unix_nsec C.int64_t) (
measurement string, fields map[string]interface{},
tags map[string]string, timestamp *time.Time) {
if acc == nil {
log.Fatal("No accumulator was active, only call this from Gather")
}
measurement = C.GoString(measurement_)
tag_list := (*[1 << 32]C.struct_tag)(unsafe.Pointer(tags_))[:tags_size]
field_list := (*[1 << 32]C.struct_field)(unsafe.Pointer(fields_))[:fields_size]

tags = make(map[string]string)
for _, tag := range tag_list {
key := C.GoString(tag.key)
value := C.GoString(tag.value)
tags[key] = value
}

fields = make(map[string]interface{})
for _, field := range field_list {
key := C.GoString(field.key)
value := convert_to_go_value(field.value)
fields[key] = value
}
timestamp = nil
if unix_sec != 0 && unix_nsec != 0 {
timestamp_ := time.Unix(int64(unix_sec), int64(unix_nsec))
timestamp = &timestamp_
}
return
}

//export add_field
func add_field(measurement_ *C.char,
tags_ *C.struct_tag, tags_size C.int,
fields_ *C.struct_field, fields_size C.int,
unix_sec, unix_nsec C.int64_t) {
measurement, fields, tags, t := add_generic(measurement_, tags_, tags_size, fields_, fields_size, unix_sec, unix_nsec)
if t != nil {
(*acc).AddFields(measurement, fields, tags, *t)
} else {
(*acc).AddFields(measurement, fields, tags)
}
}

//export add_gauge
func add_gauge(measurement_ *C.char,
tags_ *C.struct_tag, tags_size C.int,
fields_ *C.struct_field, fields_size C.int,
unix_sec, unix_nsec C.int64_t) {
measurement, fields, tags, t := add_generic(measurement_, tags_, tags_size, fields_, fields_size, unix_sec, unix_nsec)
if t != nil {
(*acc).AddGauge(measurement, fields, tags, *t)
} else {
(*acc).AddGauge(measurement, fields, tags)
}
}

//export add_counter
func add_counter(measurement_ *C.char,
tags_ *C.struct_tag, tags_size C.int,
fields_ *C.struct_field, fields_size C.int,
unix_sec, unix_nsec C.int64_t) {
measurement, fields, tags, t := add_generic(measurement_, tags_, tags_size, fields_, fields_size, unix_sec, unix_nsec)
if t != nil {
(*acc).AddCounter(measurement, fields, tags, *t)
} else {
(*acc).AddCounter(measurement, fields, tags)
}
}

//export add_summary
func add_summary(measurement_ *C.char,
tags_ *C.struct_tag, tags_size C.int,
fields_ *C.struct_field, fields_size C.int,
unix_sec, unix_nsec C.int64_t) {
measurement, fields, tags, t := add_generic(measurement_, tags_, tags_size, fields_, fields_size, unix_sec, unix_nsec)
if t != nil {
(*acc).AddSummary(measurement, fields, tags, *t)
} else {
(*acc).AddSummary(measurement, fields, tags)
}
}

//export add_histogram
func add_histogram(measurement_ *C.char,
tags_ *C.struct_tag, tags_size C.int,
fields_ *C.struct_field, fields_size C.int,
unix_sec, unix_nsec C.int64_t) {
measurement, fields, tags, t := add_generic(measurement_, tags_, tags_size, fields_, fields_size, unix_sec, unix_nsec)
if t != nil {
(*acc).AddHistogram(measurement, fields, tags, *t)
} else {
(*acc).AddHistogram(measurement, fields, tags)
}
}

func convert_to_go_value(c_value C.struct_go_value) (go_value interface{}) {
switch c_value.type_ {
case C.TYPE_INT:
go_value = int64(C.get_go_value_int(c_value))
case C.TYPE_UINT:
go_value = uint64(C.get_go_value_uint(c_value))
case C.TYPE_FLOAT:
go_value = float64(C.get_go_value_double(c_value))
case C.TYPE_BOOL:
go_value = bool(C.get_go_value_bool(c_value))
case C.TYPE_STRING:
go_value = C.GoString(C.get_go_value_string(c_value))
}
return
}