JR Recipes

In this section you can find different recipes to solve issues with jr

Dynamic AVRO

System wide templates can natively serialize to AVRO, but user/embedded templates cannot - unless you recompile JR - due to the static nature of the go libraries used. If you need to serialize with AVRO from a user template and you don’t want to recompile JR, here is how to do it. You can send JSON messages generated with JR as AVRO messages to a Kafka topic using the kafka-avro-console-producer cli tool.

For example, given the following AVRO schema:

{
  "fields": [
    {
      "name": "addressinfo",
      "type": [
        {
          "fields": [
            {
              "name": "city",
              "type": "string"
            },
            {
              "name": "street",
              "type": "string"
            },
            {
              "name": "zip",
              "type": "string"
            }
          ],
          "name": "Addressinfo",
          "type": "record"
        }
      ]
    },
    {
      "name": "name",
      "type": "string"
    },
    {
      "name": "surname",
      "type": "string"
    }
  ],
  "name": "UserInfo",
  "namespace": "example.kafka",
  "type": "record"
}

And a corresponding sample user template for JR:

{
    "addressinfo": {
        "example.kafka.Addressinfo": {
            "city": "{{city}}",
            "street": "210 Javier Run",
            "zip": "{{zip}}"
        }
    },
    "name": "{{name}}",
    "surname": "{{surname}}"
}

You can send data using the following simple command:

jr run user -f 1000ms -l | kafka-avro-console-producer --broker-list broker:<port> --topic <the_topic> --property schema.registry.url=http://<host>:<port> --property value.schema.id=<SCHEMA_ID>

Here is an example to publish to Confluent Cloud:

jr run user -f 1000ms -l | kafka-avro-console-producer --broker-list SASL_SSL://<your-cluster>.<region>.<cp>.confluent.cloud:9092 --producer.config <path_to_your>/config.properties --topic <topic> --property value.schema.id=<schema_id>  --property schema.registry.basic.auth.user.info=<yout_sr_key> --property basic.auth.credentials.source=USER_INFO --property schema.registry.url=https://<your_sr>.<region>.<cp>.confluent.cloud

Getting the Key from the Value

If the key is part of your value, the easiest way is to do something like this

{{$userid := (print "user_" (counter "user_id" 1 1 ) )}}{{set_v "KEY" $userid }}
{
    "registertime": {{integer64 1487715775521 1519273364600}},
    "userid": "{{$userid}}",
    "regionid": "Region_{{integer 1 9}}",
    "gender": "{{randoms "MALE|FEMALE|OTHER"}}"
}

In other words, adding a simple field - or a complex one like in the above example - to the context and naming it KEY will be enough. Note that this will override a key generated with the --keytemplate option

Generate CSV

JR can be used to generate random data and export them to a csv file. This can be easily achieved using a custom template; next example will show how to generate custom data with a custom template and export results to file city_temperature.csv

echo -e "city;temperature" > city_temparature.csv && jr template run -n 4 --embedded '{{city}};{{format_float "%.1f" (floating 40 5)}}' >> city_temparature.csv
city;temperature
Tampa;30.2
Tucson;36.0
Cincinnati;31.5
Houston;24.2

Get data from CSV files

You can use a CSV file as an input or data source for a template, with the fromcsv function. For example, the following command:

jr run csv_user --csv users.csv

Generates output that combines random data with values from the CSV file:

{
  "age": 30,
  "eyeColor": "blue",
  "name": "John",
  "surname": "Brown",
  "company": "Hooli",
  "email": "john.brown@emeraldcity.oz"
}

Let’s take a look at the csv_user template (included in the distribution):

{
  "age": {{integer 20 60}},
  "eyeColor": "{{randoms "blue|brown|green"}}",
  "name": "{{fromcsv "NAME"}}",
  "surname": "{{fromcsv "SURNAME"}}",
  "company": "{{company}}",
  "email": "{{lower (fromcsv "NAME") }}.{{lower (fromcsv "SURNAME") }}@emeraldcity.oz"
}

This template uses the fromcsv function, which looks for the corresponding columns in the CSV file users.csv.

Here’s an example of a sample CSV file’s content:

NAME, SURNAME
John, Brown
Mary, White

The fromcsv function retrieves the appropriate values from the specified columns, allowing you to integrate CSV data into your generated output.

Injecting Faults

The function inject may be used to inject faults in data with a given probability. The function gets three parameters: a probability, the injected value and the original one. Piping a good value to inject you can inject a fault/different value in the output, and you can mix and match any type.

Some examples:

# injecting a float instead of an integer
jr template run --embedded '{{integer 1 10 | inject 0.5 -0.001 }}'

# injecting a float instead of a string
jr template run --embedded '{{uuid | inject 0.5 -0.0001 }}'

# injecting a bad string
jr template run --embedded '{{$bad:=regex "[A-Z]{5}"}}{{city | inject 0.5 $bad }}'

You can also run this inject example directly from the command line

jr man inject --run

Insert data into a RDBMS

You can create a template that generates a SQL statement, which you can use with your RDBMS CLI tools to insert data into a database.

For example, if you have a PostgreSQL table defined like this:

CREATE TABLE Orders (
	id SERIAL PRIMARY KEY NOT NULL,
	itemid INTEGER NOT NULL,
	quantity INTEGER NOT NULL,
	customerid INTEGER NOT NULL
)

You can create a template named insert.tpl like this:

INSERT INTO Orders (itemid, quantity, customerid) VALUES ({{integer 1 1000}},{{integer 1 10}}, {{integer 1 100}} );

Copy the template to the appropriate path according to your environment, and then run jr, piping the output to your PostgreSQL server:

jr run insert -n 10  |psql -h <pgserver> -U <pg_user> -d <pg_database>

You may need to set the PGPASSWORD environment variable before running the command:

export PGPASSWORD=<pg_user_pwd>

Finally, you can check the new rows inserted with the following command:

psql -h <pgserver> -U <pg_user> -d <pg_database> -c "select * from orders"