Giter Site home page Giter Site logo

telenornms / skogul Goto Github PK

View Code? Open in Web Editor NEW
28.0 6.0 14.0 9.1 MB

Generic go-based data/metric-collector-framework for Gondul and more

License: GNU Lesser General Public License v2.1

Go 98.53% Shell 0.15% Makefile 1.24% Dockerfile 0.08%
golang influxdb mysql http metrics metrics-gathering api hacktoberfest

skogul's Introduction

image

image

image

Skogul - generic metric/data collector

Skogul is a generic tool for moving metric data around. It can serve as a collector of data, but is primarily designed to be a framework for building bridges between data collectors and storage engines.

This repository contains the Skogul library/package, and cmd/skogul, which parses a JSON-config to set up Skogul.

The release also includes extensive documentation autogenerated, provided both as a manual page (man skogul), and RST in docs/skogul.rst once built.

See also the examples in docs/examples/basics

Table of contents

Quickstart - RPM

If you're on CentOS/RHEL 7 or newer, you should use our naively built RPM, available at https://github.com/telenornms/skogul/releases/latest.

It will install skogul, set up a systemd service and install a simple configuration in /etc/skogul/conf.d/default.json.

There's also a 64-bit Linux build there, which should work for most non-RPM-based installations. But we make no attempt to really maintain it.

Quickstart - Docker

A docker image is published to ghcr.io/telenornms/skogul as of version v0.17.0. As of version v0.18.0, it is also published as "latest". See the container image repository page for details: https://github.com/telenornms/skogul/pkgs/container/skogul

Quickstart - source

Building from source is not difficult. First you need Golang. Get it at https://golang.org/dl/ (I think you want go 1.19 or newer).

Building skogul, including cloning:

$ git clone https://github.com/telenornms/skogul
(...)
$ make
$ make install

You don't have to use make - there's very little magic involved for regular building, but it will ensure -version works, along with building the auto-generated documentation.

Running make install installs the binary and default configuration, but does NOT install any systemd unit or similar.

Also see make help for other make targets.

About

Skogul collects, mutates and transmits metric data. It was written to support an extensive eco system of data collectors and storage engines in constant motion. With Skogul, the goal is to disconnect how data is collected from how it is stored: If you decide to change storage engine, you should not have to even touch your collector. Or vice versa.

It can be used for very simple setups, and expanded to large, multi-datacenter infrastructures with a mixture of new and old systems attached to it.

To accomplish this, you set up chains that define how data is received, how it is treated, where it goes and what happens if something goes wrong.

A Skogul chain is built from one or more independent receivers which receive data and pass it on to a sender. A sender can either transmit data to an external system (including an other Skogul instance), or add some internal routing logic before passing it on to one or more other senders.

image

Unlike most APIs or collectors of metrics, Skogul does NOT have a preference when it comes to storage engine. It is explicitly designed to disconnect the task of how data is collected from how it is stored.

The rationale is that the problem of writing an efficient SNMP collector should not be tightly coupled to where you store the data. And where you store the data should not be tightly coupled with how you receive it, or what you do with it.

This enables an organization to gradually shift from older to newer stacks, as Skogul can both receive data on old and new transport mechanisms, and store it both in new and old systems. That way, older collectors can continue working how they always how worked, but send data to Skogul. During testing/maturing, Skogul can store the data in both legacy system and replacement system. When the legacy system is removed, no change is needed on the side of the collector.

Extra care has been put into making it trivial to write senders and receivers.

See the package documentation over at godoc for development-related documentation: https://godoc.org/github.com/telenornms/skogul

More discussion on architecture can be found in docs/.

Modules

Skogul is all based around modules. We started out with three modules, but today we have a total of five different module types. To see every module, use skogul -help, read the manual, or simply look in the receiver, sender, parser, encoder and transformer directory and read the auto.go file there which lists all modules.

Each family of module has its own section in the JSON configuration file.

While all modules are fundamentally equal, receivers and senders are so important that they are a little bit more equal, so we call them core modules.

image

Core modules

Senders and receivers

There are two essential module types, the receiver which defines how data is acquired, and senders that determine what to do with the data. A handler is just a collection of parser, optional transformer and reference to the first sender.

Commonly used receivers are the HTTP receiver, UDP, kafka receiver (consumer), various file receivers, SQL receiver

Senders all have the same general API, but come in two distinct types

External senders

External senders transmit data out of Skogul and are the classic and easy-to-understand senders. Examples are InfluxDB sender to store data in InfluxDB, UDP sender, Kafka sender (producer), SQL sender, MQTT, and more.

The debug or "print" sender is a little special: It just prints data to stdout and is HIGHLY useful for testing.

Internal/Logic senders

Logical senders are used internally to route or do something related with data. The by far most important internal sender is the batch sender, which accepts data, batches it into user-defined sizes, then passes them on to an other sender. There are a large amount of small but important logical senders that can be combined to form powerful chains.

Other dev favorites are: The count sender for getting statistics about how much data passes through Skogul, the switch sender for sending data to different other senders based on metadata, dupe sender for sending the same data to multiple other senders, the null sender for simply discarding data,

Support modules

Additionally, three support-type modules exists:

Parsers

The parser takes a set of bytes received and decodes it into a Skogul internal container. E.g.: JSON decoding, protocol buffers for Juniper-data, Influx Line protocol data, etc and is used by receivers through handlers.

Encoders

The encoder does the opposite: It takes an internal Skogul container and encodes it as a byte stream for external tranmission. Today, only a small amount of senders use encoders, as they are quite new, but they will be used more extensively in the future. Currently, only JSON is supported. More to come.

Transformers

Transformers are used to, you guessed it, transform or mutate parsed containers. Typically used to re-arrange source data to better match target data, to add metadata, or to sanitize data.

Implicit modules

All modules can be defined in configuration, but several modules have zero configuration options, or very common options. E.g.: The skogul parser doesn't require any configuration to work, the debug sender works fine without any settings, the now transformer doesn't need any configuration to add current time to a metric. To save you from having to define a whole lot of empty modules, these type of modules can be referenced by their implementation name (class, if you like) and an instance will be created behind the scenes. These are listed as "auto modules" in the manual page.

E.g., without this feature:

{
        "receivers": {
                "foo": {
                        "type": "test",
                        "handler": "myhandler"
                }
        },
"handlers": {
    "myhandler": {
        "parser": "skogul",
        "sender": "debug"
    }
},
        "parsers": {
                "skogul": {
                        "type": "skogul"
                }
        },
        "senders": {
                "debug": {
                        "type": "debug"
                }
        }
}

But since the Skogul parser and the debug sender has no configuration, you can just omit their definition and Skogul will implicitly create them for you:

{
        "receivers": {
                "foo": {
                        "type": "test",
                        "handler": "myhandler"
                }
        },
"handlers": {
    "myhandler": {
        "parser": "json",
        "sender": "debug"
    }
}
}

Performance

Skogul is meant to scale well. Early tests on a laptop proved to work very well:

image

The above graph is from a very simple test on a laptop (with a quad core i7), using the provided tester to write data to influxdb. It demonstrates that despite well-known weaknesses at the time (specially in the influx-writer), we're able to push roughly 600-800k values/s through Skogul. This has since been exceeded.

This was an early test, and since then Skogul has been run in production on large scale systems, and generally out-performs anything it communicates with.

Name

Skogul is a Valkyrie. After extensive research (5 minutes on Wikipedia with a cross-check on duckduckgo), this name was selected because it is reasonably unique and is also a Valkyrie, like Gondul, a sister-project.

Hacking

There is little "exotic" about Skogul hacking, so the following sections are aimed mostly at people who are unfamiliar with Go.

A few sources for more documentation:

  • docs/CODE_OF_CONDUCT.md
  • docs/CONTRIBUTING
  • docs/CODING
  • doc.go

Testing

In short: Use make check. It will run go test -short ./... and various other checks. There's also make covergui to do coverage analysis and open it in a browser.

make check is run on every commit.

Use make fmtfix to fix formatting issues, which also makes sure to not mess with the bundled/generated go files.

Documentation

Documentation comes in two forms. One is aimed at end-users. This is provided mainly by adding proper labels to your data structures (see any sender or receiver implementation), and through hard-coded text found in cmd/skogul/main.go. In addition to this, stand-alone examples of setups are provided in the examples/ directory.

For development, documentation is written and maintained using code comments and runnable examples, following the godoc approach. Some architecture comments are kept in docs/, but by and large, documentation should be consumed from godoc.

See https://godoc.org/github.com/telenornms/skogul for the online version, or use go doc github.com/telenornms/skogul or similar, as you would any other go package.

Examples are part of the test suite and thus extracted from *_test.go where applicable. But aren't really used much.

Roadmap

We are doing frequent releases on github. I honestly don't know why no 1.0 release has been made. Mainly lazyness, we've been "almost there" for 2+ years.

Overall, the core modules and the scaffolding is getting pretty good.

The bigger things moving right now except new modules is logging, which has never been quite right, and dealing with some legacy/deprecation.

Similarly, test cases need to be refreshed. Tests are written very isolated, and a good bit of spaghetti-logic has arisen. We have decent coverage, but it's getting trickier to scale test case writing.

We also need better integration tests now that Skogul integrates with a wide variety of services.

Other than that, there are modules to be written and features to be added which are mostly a matter of what needs arise.

skogul's People

Contributors

burntcarrot avatar dependabot[bot] avatar eiriktaa avatar kamilernerd avatar kristianlyng avatar moogacs avatar n-holmstedt avatar roshininara avatar sklirg avatar vnragavan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

skogul's Issues

Migrate the code from log to logrus

Logrus has been introduced, but we need to migrate all code to it.

I think we also need a discussion/policy on how/when to log at all.

In general, I'm thinking:

  1. Code should not use log.Fatal unless it's package main: it prevents trivial testing.
  2. Successful code paths should not log. Exceptions can be made for important debugging, but for things like transformers, intermediary senders, etc, I'd prefer if it didn't log on OK code paths. It is a performance hit...
  3. If we return error, logging should be "trace" at most - the calling code should log the error at higher log levels instead (e.g.: if HTTP sender fails, log trace, and throw error, that way, the retry sender can decide what to log).
  4. If we discard actual errors: Log with at least info if it is a common setup. Preferably higher level.
  5. If we handle errors (e.g.: fallback-sender), log with debug.

I think this list needs to be improved/revised as we see how the logging works in real life, but some sort of common principles are needed.

data model: Reject metadata->timestamp keys

If a collector is implemented incorrectly it is easy to end up posting timestamp as metadata in addition to regular timestamp. While this could be allowed, it is safe to assume that this is almost always a mistake.

Therefore, the data validation should check for metadata fields named "timestamp" and throw an error. Example of issue:

{
 "metrics": [ {
    "timestamp": "2019-04-02T16:00:00Z",
    "metadata": { "device": "foo", "timestamp": "2019-04-02T16:00:00Z" },
    "data": { "something": 123123 }
  } ]
}

Chore: Overhaul tests with more modern methods and unify re-usable bits

While test-coverage is OK-ish, older tests have not been updated to use newer methods when suitable.

Specifically, a lot of tests define data structures by hand instead of just providing a configuration-snippet, which would be both more readable and implicitly test the configurability.

Additionally, many tests have helper-functions that are semi-reusable, like verify that metadata is transformed the way we expect, or generating valid containers. This re-use is sort of messy now.

Config: unused items are not revealed to the user

If three senders are specified, but only one is used, the user will never know. This could lead to situations where a user wants to direct data to two different locations, but accidentally directs it to the same place.

I'm thinking warning is the suitable response, possibly with an option to make it critical.

Influx: Needs a more mature way to re-use connections etc

Pretty sure this is killing performance.

Might also be worth it to use this as an example of how to deal with concurrency. The way we are doing it now works OK simply because we are setting up new requests all the time, but that should probably die in a fire. A better model might be to have a pool of influx-writers internally, to serialize access but not limit ourself to a single instance.

But that should be a sender in itself?

I think what makes sense right now is that the influx writer only has a single HTTP connection it will (re-)-use, and that a future Sender provides a worker-pool-like feature. That way the influx-code is nice and simple.

It will still require locking, I suppose.

Add RequireMetadataKey sender

The idea is to optionally enforce certain metadata fields. This can make particular sense "further down the chain" to ensure that upstream data sources follow policies and identify themself.

The same Sender should also support OPTIONAL value enforcement. That way, we can have a central Skogul enforce that data from DC1 is always tagged with DC1, but downstream, we only ensure that the "dc" tag is set at all.

Config errors are cryptic at best.

While the documentation is getting to be reasonably good, the errors that the config engine reports are horrid. Need a good general-purpose approach to report errors.

Write/re-write log receiver, using logrus

We need better logging, and #30 introduces logrus.

The log receiver needs to be updated to handle this, and should:

  1. Ensure the initial read-path is quick and non-blocking. It should just read the logs and place them on a buffered channel, then move on (or similar). Code should be able to log extensively without having to worry about log performance at all. If logrus can't satisfy this, we have a problem.

  2. Extract fields into metadata to as great an extent as possible.

  3. Leverage transformers for filtering, but a basic log-level filter is OK. Simplicity of configuration is key: People will expect the log receiver to support filtering on log levels, so even if you can use a transformer to do that, it will be such a common use case that it should live in the receiver.

Note that this issue is NOT about introducing logrus in general, but just the logrus-capable receiver, so we can forward logs.

We also need to address suppressing log output to stdout. I don't have a clear picture of how we want to do that. But I'm thinking we want to be able to echo e.g. warnings and above to stdout, while sending everything (trace, info, debug, warn, etc) down to the handler. This will allow us to have extensive logs in a log system (splunk/database), while still getting sensible debug-output.

Logrus also makes it easier to avoid loops: We should probably set a metadatafield indicating that this has passed through the log receiver, so we don't end up in feedback loops if splunk is unresponsive. Not entirely sure how that will work, though.

Config verification does the "wrong" ToLower

Given the following diff for debug output:

diff --git a/config/parse.go b/config/parse.go
index d2665e0..5897aec 100644
--- a/config/parse.go
+++ b/config/parse.go
@@ -417,13 +417,21 @@ func findFieldsOfStruct(T reflect.Type) []string {
 
 func getRelevantRawConfigSection(rawConfig *map[string]interface{}, family, section string) map[string]interface{} {
        // log.Debugf("Fetching config section '%s' for '%s' from %v", section, family, rawConfig)
-       return (*rawConfig)[family].(map[string]interface{})[strings.ToLower(section)].(map[string]interface{})
+       cast1,ok := (*rawConfig)[family].(map[string]interface{})
+       if !ok {
+               return nil
+       }
+       cast2,ok := cast1[strings.ToLower(section)].(map[string]interface{})
+       if !ok { 
+               log.Warnf("Failed to cast config section for section %s to map[string]interface{}",strings.ToLower(section))
+               return nil
+       }
+       return cast2
 }
 
 func verifyOnlyRequiredConfigProps(rawConfig *map[string]interface{}, family, handler string, T reflect.Type) []string {
        requiredProps := findFieldsOfStruct(T)
        log.Debugf("Required fields: %v", requiredProps)
-
        relevantConfig := getRelevantRawConfigSection(rawConfig, family, handler)
 
        superfluousProperties := make([]string, 0)

You get the following errors when a transformer is named Optics_diag and interfaceExp_stats:

WARN[0000] Failed to cast config section for section optics_diag to map[string]interface{} 
WARN[0000] Failed to cast config section for section interfaceexp_stats to map[string]interface{} 

Without the patch, skogul will panic instead. This was revealed by my transformer-tests, but would apply to senders/handlers/receivers as well.

That code in general makes sense to some degree, since we should always verify that our casting works.

Conditional transformation based on a field in the metadata

Feature request

I propose being able to apply a transformer to an incoming metric based on a conditional, e.g. matching it against a metadata field (sensorName, systemId, ...).

Rationale

It is possible to apply multiple transformers to the same incoming container/metric, e.g. to first split it and then flatten it.

All transformers are being tried before the container is handed over to the sender.

Currently, we have configured 10 transformers where approximately 3 transformers are run per metric (split, extract, flatten). The other ones silently fail, e.g. because the target field for extract or flatten doesn't exist. I think this is "abusing" the way transformers work.

I find two potential pain points of this.

  1. The configuration can be hard to maintain simply because of the number of transformers applied to the same handler.
  2. A simple transformer might apply to multiple metrics which could end up transforming/mangling the metrics in some way the user doesn't want or expect it to do, and there is no way around this (it's nice that it can happen for all of the metrics, e.g. extracting the interface name from the data set, but I think it should be possible to skip it as well)

Furthermore, I haven't really dug deep regarding this, but some of the transformers might run for a bit before they fail which could have an impact on performance. E.g. extracting nested json-objects by casting a metric into map[string]interface{} on multiple levels before it realises the field it actually wants to extract doesn't actually exist.

Potential solution

This feature could be implemented in the transformers, but at that point you wouldn't really solve the maintenance of the configuration issue.

I think that extending the handlers with a configuration option for mapping a transformer to a conditional would be the way to go.

Potential configuration:

{
  "receivers": {
    "udp": {
      "type": "udp",
      "address": "[::1]:1337",
      "handler": "next"
    }
  },
  
  "handlers": {
    "next": {
      "parser": "json",
      "transformers": [
        {
          "transformer": "interface_info",
          "when": "sensorName",
          "is": "junos_system_linecard_interface"
        }
      ]
    }
  },
  
  "transformers": {
    "interface_info": {
      "type": "split",
      "field": "if_name"
    }
  }
}

No decent context-aware validation of configuration

It is up to each sender/receiver to verify initial configuration, but it might be useful to provide an interface that allows them to provide a verification function.

One reason this is relevant is that it will allow an operator to verify a new configuration before the old skogul instance is stopped.

An other reason is that for things like errors that are diverted to other sources, the relevant sender might not even execute at all for quite some time, so configuration errors might not be evident at all until much later.

Request log for http receiver

The HTTP receiver currently doesn't really log much. It gives reasonably good responses, but for debugging, it can be tricky to know what's going on.

This issue is about adding an option to the http receiver, found in 'http/receiver.go' that lets the administrator enable/disable request logs for successfully received requests. It should log this as either Debug or Info, possibly with a difference between OK requests and invalid requests.

The HTTP receiver already logs some errors, but not all, so ideally that should be improved as well so we always log. I'm thinking adding logging to ServeHTTP, possibly removing it/changing it in handle(), but it's up to whoever decides to do the job.

Testing: Provide the scaffolding for doing config-file-based testing.

A complete config file requires senders, receivers and handlers. But the actual config file parser does not.

We should leverage this to make it easier to write tests that are based on real config files.

That way, a config might be

{
   "senders": {
      "foo": { 
        "type": "fallback",
        "next": ["fail","ok","ignore" ]
      },
      "fail": { 
          "type": "forwardfail",
          "next": "fake-fail"
      },
      "fake-fail": {"type": "tester" },
      "ok": {"type": "tester" },
      "ignore": {"type": "tester" }
   }
}

The test itself will then reference c.Senders["foo"].Sender for testing, and check the count on the others....

It will require that the test-sender is exported, but that's ok.

Transform content of metrics/metadata keys

E.g. Juniper sends systemId of the form "hostname-reX:IP", and we want to extract "hostname" from it. And the sensorName is typicially "foo:/foo-ish:/foo/foo/foo:PFE" where we just want "foo".

I'd like some benchmarks if we're doing a general purpose regex-thing, but it should be fine.

A transformer should probably:

  1. Be able to read and write from the same variable (e.g.: systemId ~= s/-re.*$//)
  2. Be able to read from a different variable than it writes to (E.g.: keep the original. systemIP = systemId; systemIP ~= s/^.*://)

Maybe something like:

  "type": "regex",
  "source": "systemId",
  "target":  "hostname",
  "find": "^[^-]*"

or similar?

We probably want both "replace" and "find"?

Influx sender should handle nested metrics better

Today we just blindly marshal metrics into influx line format without much attention payed to the type of data. This causes Skogul to send invalid writes to influx, which is pretty bad.

The influx sender should evaluate the metric data and either fail/error out on nested structures, or do something that is protocol-correct with it - not sure what.

Extract to metadata should extract, not copy

Today, extract will copy data, not move it. This creates problems for things like influxdb and is semantically incorrect. An extraction, semantically, suggest it is moved from one place to an other.

If we want a copy, we should have a separate function for that. As such, extract should remove the original.

Configure log level

We need a flag for setting the log-level in skogul, now that we have code that actually uses it... I also want to have some more sensible output defaults (The [0000] of WARN[0000] made zero sense to me until I literally read the source code).

I think we should offer runtime control through flags for:

  • log level/detail
  • disabling/enabling (full) timestamps (you don't want timestamps in a systemd-context, since journald will take care of that)

While we could offer more options, limiting the flags to what we really need should be a priority.

Add username/password support to http receiver

Step one is just plain hardcoded basic auth. In the future, more advanced schemes may be necessary (e.g.: ldap or oauth etc). This ticket just deals with the simplest example, but SHOULD anticipate:

  1. That checking authentication and authorization needs to be modular
  2. That it needs to be fast

Integration tests with external services

As nice as 'go test' is, we need integration testing as well. E.g.: Build, set up influx, do some tests, verify data in influx, pull things down.

I've seen some examples, but I feel like the "go"-based examples I've seen are bit too introvert. It doesn't make sense to me to use go to run 'docker run --name influx -d influxdb; sleep 5; run-tests; docker kill....'.... but there must be some better examples/practices out there.

Extend http-receiver with multiple paths/senders

We need to be able to accept writes on multiple paths and handle them differently.

Something simple like re-using the net/http path-mapping seems appropriate.

E.g.: Set up a generic postgres/influx receiver at /api/write/collect, but allow special handling of /api/write/collect/snmp.

Support being able to configure the flattening separator

#33 introduced support for being able to "flatten" a nested data structure. This preserves the hierarchy of the nested object, so {"some": { "sweet": "data" }} becomes { "some__sweet": "data" }. The separator is hardcoded to double underscores but this should be configurable by the user in the config.

MySQL sender

Almost a direct copy of the postgres-sender, but for MySQL.

Should use a very simple schema in the early versions.

Discussion: Partial send failures

Issue #25 illustrates a problem that will arise when using large, consolidated data stores that do not accept arbitrary data. Specially if combined with batching of data.

A container could be sent to a sender where the sender knows how to handle some, but not all metrics. Today, the API doesn't provide any method of handling this properly. The sender has to decide what to do:

  1. Send whatever it can send
  2. Return error regardless of whether some metrics were successfully handled
  3. Return ok as long as just one metric failed
  4. ????

This is particularly problematic when HA is introduced, e.g. with fallback sender. If a producer starts sending data that a sender can't handle and it gets batched together with "good" data, the fallback sender will send all data - even data successfully written - to the next sender.

I don't have any perfect answer for this. But I'm thinking along the lines of introducing new error types: skogul.PartialFailure or similar, similar to:

type PartialFailure struct {
    Source string
    Reason string
    Succeeded []*Metrics
    Failed []*Metrics
}

InfluxDB: Configurable behavior on single-metric marshaling errors

#31 has a bit where the influxdb sender ignores metrics it doesn't know how to handle, but will write the remainder of them. This should be configurable.

The scenarios are:

  1. Mixed data - write what you can, report errors, but don't fail. E.g.: Do not return error, which would trigger alternate paths.
  2. Non-mixed data: Everything fails. This should always be an error?

I'm thinking the option should be something along the lines of "write partially marshalled data", potentially with a second option/teritary option where partially marshalled data is written, but logged/warned about. Either way, if we successfully write anything we should not return error, since that can cause data to be duplicated.

RabbitMQ queue-sender

Send data to rabbitmq. Good first case since it's a plain copy of influx or postgres sender, just add rabbitmq-integration instead.

Write a handful of go test-tests

This issue is meant to just get things started on unit-testing. Basically just write tests for "whatever", but in a representative manner.

Allow influxdb to pick up which measurement to write to from metadata

Today the InfluxDB sender gets its measurement from initialization of the sender, meaning that all data written to that sender will go to the same measurement.

There's no need for this. Instead, we can also offer a configuration variable, e.g. "MeasurementFromMetadata", which, if specified, tells the influxdb sender to read the metadatafield specified and use that as the measurement to write to.

It should probably still have some sort of fallback or default.

Syntax errors are offset incorrectly when tabs are used

I knew this going in, but I never fixed it/wrote an issue on it....

When calculate how far to indent when underlining syntax errors, we don't account for how some characters are wider than others. Most critical is tabs, which tend to be 8 character wide, but this can also include other none-1-char-wide-chars (e.g.: emojis).

Random test-case reveals this.

offset

New Sender: Batch-builder

Accepts a single Next Sender. Data sent to it is batched up into a larger set, then forwarded periodically. Typical use-cases:

Right after a HTTP receiver to gather up multiple statistics.

Before a "write-to-disk" fallback.

Must decide if it should block or not. The benefit of blocking is that we can still return status messages to clients while batching up data from multiple sources. Then a simple buffer-sender can deal with the alternate scenario where we want to ACK to clients without waiting around for stuff to "hit disk".

Document architectural guide lines

A document listing certain pricniples of the design is in order. It should include such things as:

  1. Senders are not allowed to modify metrics. Ever.
  2. If a sender creates a new container, that container should never be sent to a new sender direct, but to a handler.
  3. A transformer should not set up multiple references to the same object/key (E.g.: copy the content, not a reference).
  4. Receivers should, by default, use multiple go routines where possible.

And so on. This is not a comprehensive list, but the document should list these "rules" so they are easier to discuss and follow. It will also mean that policy/rules can be discussed in pull requests in a more transparent way.

New sender: FlatFilter

The idea is to provide a sender with two handlers as config: Flat and Non-Flat.

For metrics received that are "flat", e.g., data and metadata match map[string](string|number|bool), the metrics will be passed on to the flat-handler, while others will end up on non-flat.

This will allow us to stick it in front of influx as a last-chance to divert non-flat metrics to, e.g., postgres, where we can store Anything as long as it can be marshalled to JSON.

Postgres: Move metadata into a separate table

mock/pseudocode:

select metadataid from metadata where metadata.metadata = '$metadata'
if 0 results: insert ..... fetch metadataid.
insert into data (ts,metadataid,data) (ts,$id-from-above,data) ....

I have the schema here somewhere that works well.... This allows us to have efficient indexes on metadata almost regardless of the size. While we can still have decent indexes today, the storage-size is much better for the above approach. And it is less vulnerable if we end up with json-structures that aren't flat, and thus aren't really indexable.

HTTP receiver: Authorize based of contents of client certificate

#40 is about authenticating with a client certificate, but this issue should handle how we can carry out authorization based on client certificates.

E.g.: Even if a client has a valid certificate, we want to be able to distinguish one client from an other.

This depends on #40 being completed.

Add mechanic for exposing documentation for custom data structures

The HTTP receiver and the Switch transformer both use a custom struct/type as part of the config. But we don't expose the documentation for it.

I propose we add an optional 'custom data structures'-part to the auto-system, so you can inform the auto-system that these items have custom data strctures that it needs to expose. Ideally we shouldn't require this, since it's possible to do this by reflection, but the complexity of doing it through reflection versus just requiring an explicit declaration is such that I don't want to go down that road.

This is a reasonably high priority issue, since we currently have undocumented security-features.

Benchmark UDP receiver with protobuf and json parser

The benchmarks for the parsers have revealed a difference in performance that's interesting. The benchmarking of http revealed a flawed implementation.

Having benchmarks for UDP will be very interesting...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.