Giter Club home page Giter Club logo

xk6-output-plugin's Introduction

xk6-output-plugin

Write k6 output extension as dynamically loadable plugin

The xk6-output-plugin is a k6 output extension that allows the use of dynamically loaded output plugins.

k6 provides many options for output management. In addition, output extensions can be made to meet individual needs. However, a custom k6 build is required to use the output extensions, and the extensions can only be created in the go programming language. The xk6-output-plugin makes custom output handling simpler and more convenient.

Features

  • output plugins can be created using your favorite programming language (e.g. go, JavaScript, Python)
  • output plugins can be created and used without rebuilding the k6 executable
  • output plugins do not increase the size of the k6 executable
  • the output plugins can be distributed independently of the k6 binary

Examples

The examples directory contains examples of how to use different programming languages to write plugin.

Simple examples:

Python
import datetime
import logging

from xk6_output_plugin_py.output import serve, Output, Info, MetricType, ValueType

class Example(Output):
  def Init(self, params):
    logging.info("init")

    return Info(description="example-py plugin")

  def Start(self):
    logging.info("start")

  def Stop(self):
    logging.info("stop")

  def AddMetrics(self, metrics):
    logging.info("metrics")
    for metric in metrics:
      logging.info(
        metric.name,
        extra={
          "metric.type": MetricType.Name(metric.type),
          "metric.contains": ValueType.Name(metric.contains),
        },
      )

  def AddSamples(self, samples):
    logging.info("samples")
    for sample in samples:
      t = datetime.datetime.fromtimestamp(
        sample.time / 1000.0, tz=datetime.timezone.utc
      )

      logging.info(
        sample.metric,
        extra={"sample.time": t, "sample.value": sample.value},
      )

if __name__ == "__main__":
  serve(Example())
JavaScript
import { serve } from 'xk6-output-plugin-js'

class Example {
  init (params) {
    console.info('init')
    return { description: 'example-js plugin' }
  }

  start () {
    console.info('start')
  }

  stop () {
    console.info('stop')
  }

  addMetrics (metrics) {
    console.info('metrics')
    metrics.forEach(metric => {
      console.info(
        { 'metric.type': metric.type, 'metric.contains': metric.contains },
        metric.name
      )
    })
  }

  addSamples (samples) {
    console.info('samples')
    samples.forEach(sample => {
      console.info(
        { 'sample.time': new Date(sample.time).toISOString(), 'sample.value': sample.value },
        sample.metric
      )
    })
  }
}

serve(new Example())
go
package main

import (
  "context"
  "time"

  "github.com/hashicorp/go-hclog"
  "github.com/szkiba/xk6-output-plugin-go/output"
)

type example struct{}

func (e *example) Init(ctx context.Context, params *output.Params) (*output.Info, error) {
  hclog.L().Info("init")

  return &output.Info{Description: "example-go plugin"}, nil // nolint:exhaustruct
}

func (e *example) Start(ctx context.Context) error {
  hclog.L().Info("start")

  return nil
}

func (e *example) Stop(ctx context.Context) error {
  hclog.L().Info("stop")

  return nil
}

func (e *example) AddMetrics(ctx context.Context, metrics []*output.Metric) error {
  hclog.L().Info("metrics")

  for _, metric := range metrics {
    hclog.L().Info(metric.Name,
      "metric.type", metric.Type.String(),
      "metric.contains", metric.Contains.String(),
    )
  }

  return nil
}

func (e *example) AddSamples(ctx context.Context, samples []*output.Sample) error {
  hclog.L().Info("samples")

  for _, sample := range samples {
    hclog.L().Info(sample.Metric,
      "sample.time", time.UnixMilli(sample.Time).Format(time.RFC3339),
      "sample.value", sample.Value,
    )
  }

  return nil
}

func main() {
  output.Serve(new(example))
}

Why not JSON?

A similar approach to the output plugin can also be achieved by processing the output generated by the k6 json output extension by an external program.

Why use the output plugin instead of processing JSON output?

  • type safe API
  • simpler callback-based processing
  • structured logging to k6 log output
  • real time result processing

How It Works?

The plugin is a local gRPC service that the xk6-output-plugin starts automatically during k6 startup and stops before k6 stops.

Output plugins are managed using the HashiCorp go-plugin.

Performance

Metric samples are buffered by the xk6-output-plugin for one second (by default) and then the plugin is called. The call per second is frequent enough for real-time processing, yet infrequent enough not to cause performance issues while running the test. The grpc call itself takes place locally through a continuously open connection, so its overhead is minimal.

The duration of buffering can be set by the plugin with the buffering variable in the Init response. Its value specifies the buffering duration in milliseconds. The default is 1000ms, which is one second. Its minimum value is 200ms.

Poliglot

One of the big advantages of output plugins is that practically any programming language can be used, which is supported by grpc for server writing.

Although the go programming language is popular, its popularity does not reach the popularity of, for example, Python or JavaScript languages. With the support of these languages, the range of developers who can create an output plugin in their favorite programming language has been significantly expanded.

Helpers

Based on the protobuf descriptor and the HashiCorp go-plugin documentation, the output plugin can be created in any programming language supported by gRPC.

Plugin development is facilitated by a helper package in the following programming languages:

Usage

The output plugin is an executable program whose name must (for security reasons) begin with the string xk6-output-plugin-. This is followed by the actual name of the plugin, which can be used to refer to it. The reference can of course also contain the full name with the prefix xk6-output-plugin-. The two reference below specify the same plugin:

./k6 run --out=plugin=example script.js
./k6 run --out=plugin=xk6-output-plugin-example script.js

The plugin is run by taking the PATH environment variable into account, unless the reference also contains a path. The reference below runs the file named xk6-output-plugin-example from the plugins directory in the current directory:

./k6 run --out=plugin=./plugins/example script.js

Configuration

Output plugins can be configured using command line arguments. Arguments can be passed to the plugin in the usual way after the name of the plugin. In this case, the entire k6 output extension parameter must be protected with apostrophes.

./k6 run --out='plugin=example -flag value' script.js

The output plugin can also be configured with environment variables. The environment variables specified during the execution of the k6 command are received by the plugin via the Init() call. These variables are available in the map named Environment of the Params parameter.

./k6 run -e var=value --out=plugin=example script.js

Download

You can download pre-built k6 binaries from Releases page. Check Packages page for pre-built k6 Docker images.

Build

To build a k6 binary with this extension, first ensure you have the prerequisites:

Then:

  1. Download xk6:
$ go install go.k6.io/xk6/cmd/xk6@latest
  1. Build the binary:
$ xk6 build --with github.com/szkiba/xk6-output-plugin@latest

Docker

You can also use pre-built k6 image within a Docker container. In order to do that, you will need to execute something like the following:

Linux

docker run -v $(pwd):/scripts -it --rm ghcr.io/szkiba/xk6-output-plugin:latest run --out=plugin=XXX /scripts/script.js

Windows

docker run -v %cd%:/scripts -it --rm ghcr.io/szkiba/xk6-output-plugin:latest run --out=plugin=XXX /scripts/script.js

xk6-output-plugin's People

Contributors

mstoykov avatar szkiba avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

mstoykov

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.