InfluxDB.Client 4.17.0-dev.14044

This is a prerelease version of InfluxDB.Client.
dotnet add package InfluxDB.Client --version 4.17.0-dev.14044
NuGet\Install-Package InfluxDB.Client -Version 4.17.0-dev.14044
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="InfluxDB.Client" Version="4.17.0-dev.14044" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add InfluxDB.Client --version 4.17.0-dev.14044
#r "nuget: InfluxDB.Client, 4.17.0-dev.14044"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install InfluxDB.Client as a Cake Addin
#addin nuget:?package=InfluxDB.Client&version=4.17.0-dev.14044&prerelease

// Install InfluxDB.Client as a Cake Tool
#tool nuget:?package=InfluxDB.Client&version=4.17.0-dev.14044&prerelease

InfluxDB.Client

CircleCI

The reference client that allows query, write and management (bucket, organization, users) for the InfluxDB 2.x.

Documentation

This section contains links to the client library documentation.

Features

Queries

For querying data we use QueryApi that allow perform asynchronous, streaming, synchronous and also use raw query response.

Asynchronous Query

The asynchronous query is not intended for large query results because the Flux response can be potentially unbound.

using System;
using System.Threading.Tasks;
using InfluxDB.Client;

namespace Examples
{
    public static class AsynchronousQuery
    {
        private static readonly string Token = "";

        public static async Task Main()
        {
            using var client = new InfluxDBClient("http://localhost:8086", Token);

            var flux = "from(bucket:\"temperature-sensors\") |> range(start: 0)";
            
            var queryApi = client.GetQueryApi();

            //
            // QueryData
            //
            var tables = await queryApi.QueryAsync(flux, "org_id");
            tables.ForEach(table =>
            {
                table.Records.ForEach(record =>
                {
                    Console.WriteLine($"{record.GetTime()}: {record.GetValueByKey("_value")}");
                });
            });
        }        
    }
}

The asynchronous query offers a possibility map FluxRecords to POCO:

using System;
using System.Threading.Tasks;
using InfluxDB.Client;
using InfluxDB.Client.Core;

namespace Examples
{
    public static class AsynchronousQuery
    {
        private static readonly string Token = "";

        public static async Task Main()
        {
            using var client = new InfluxDBClient("http://localhost:8086", Token);

            var flux = "from(bucket:\"temperature-sensors\") |> range(start: 0)";
            
            var queryApi = client.GetQueryApi();

            //
            // QueryData
            //
            var temperatures = await queryApi.QueryAsync<Temperature>(flux, "org_id");
            temperatures.ForEach(temperature =>
            {
                Console.WriteLine($"{temperature.Location}: {temperature.Value} at {temperature.Time}");
            });
        }  
        
        [Measurement("temperature")]
        private class Temperature
        {
            [Column("location", IsTag = true)] public string Location { get; set; }

            [Column("value")] public double Value { get; set; }

            [Column(IsTimestamp = true)] public DateTime Time { get; set; }
        }
    }
}

Streaming Query

The Streaming query offers possibility to process unbound query and allow user to handle exceptions, stop receiving more results and notify that all data arrived.

using System;
using System.Threading.Tasks;
using InfluxDB.Client;

namespace Examples
{
    public static class StreamingQuery
    {
        private static readonly string Token = "";

        public static async Task Main()
        {
            using var client = new InfluxDBClient("http://localhost:8086", Token);

            var flux = "from(bucket:\"temperature-sensors\") |> range(start: 0)";

            var queryApi = client.GetQueryApi();

            //
            // QueryData
            //
            await queryApi.QueryAsync(flux, record =>
            {
                //
                // The callback to consume a FluxRecord.
                //
                Console.WriteLine($"{record.GetTime()}: {record.GetValueByKey("_value")}");
            }, exception =>
            {
                //
                // The callback to consume any error notification.
                //
                Console.WriteLine($"Error occurred: {exception.Message}");
            }, () =>
            {
                //
                // The callback to consume a notification about successfully end of stream.
                //
                Console.WriteLine("Query completed");
            }, "org_id");
        }
    }
}

And there is also a possibility map FluxRecords to POCO:

using System;
using System.Threading.Tasks;
using InfluxDB.Client;
using InfluxDB.Client.Core;

namespace Examples
{
    public static class StreamingQuery
    {
        private static readonly string Token = "";

        public static async Task Main()
        {
            using var client = new InfluxDBClient("http://localhost:8086", Token);

            var flux = "from(bucket:\"temperature-sensors\") |> range(start: 0)";
            
            var queryApi = client.GetQueryApi();

            //
            // QueryData
            //
            await queryApi.QueryAsync<Temperature>(flux, temperature =>
            {
                //
                // The callback to consume a FluxRecord mapped to POCO.
                //
                Console.WriteLine($"{temperature.Location}: {temperature.Value} at {temperature.Time}");
            }, org: "org_id");
        }  
        
        [Measurement("temperature")]
        private class Temperature
        {
            [Column("location", IsTag = true)] public string Location { get; set; }

            [Column("value")] public double Value { get; set; }

            [Column(IsTimestamp = true)] public DateTime Time { get; set; }
        }
    }
}

Raw Query

The Raw query allows direct processing original CSV response:

using System;
using System.Threading.Tasks;
using InfluxDB.Client;

namespace Examples
{
    public static class RawQuery
    {
        private static readonly string Token = "";

        public static async Task Main()
        {
            using var client = new InfluxDBClient("http://localhost:8086", Token);

            var flux = "from(bucket:\"temperature-sensors\") |> range(start: 0)";

            var queryApi = client.GetQueryApi();

            //
            // QueryData
            //
            var csv = await queryApi.QueryRawAsync(flux, org: "org_id");
            
            Console.WriteLine($"CSV response: {csv}");
        }
    }
}

The Streaming version allows processing line by line:

using System;
using System.Threading.Tasks;
using InfluxDB.Client;

namespace Examples
{
    public static class RawQueryAsynchronous
    {
        private static readonly string Token = "";

        public static async Task Main()
        {
            using var client = new InfluxDBClient("http://localhost:8086", Token);

            var flux = "from(bucket:\"temperature-sensors\") |> range(start: 0)";

            var queryApi = client.GetQueryApi();

            //
            // QueryData
            //
            await queryApi.QueryRawAsync(flux, line =>
            {
                //
                // The callback to consume a line of CSV response
                //
                Console.WriteLine($"Response: {line}");
            }, org: "org_id");
        }
    }
}

Synchronous query

The synchronous query is not intended for large query results because the response can be potentially unbound.

using System;
using InfluxDB.Client;

namespace Examples
{
    public static class SynchronousQuery
    {
        public static void Main()
        {
            using var client = new InfluxDBClient("http://localhost:9999", "my-token");

            const string query = "from(bucket:\"my-bucket\") |> range(start: 0)";
           
            //
            // QueryData
            //
            var queryApi = client.GetQueryApiSync();
            var tables = queryApi.QuerySync(query, "my-org");
            
            //
            // Process results
            //
            tables.ForEach(table =>
            {
                table.Records.ForEach(record =>
                {
                    Console.WriteLine($"{record.GetTime()}: {record.GetValueByKey("_value")}");
                });
            });
        }
    }
}

Writes

For writing data we use WriteApi or WriteApiAsync which is simplified version of WriteApi without batching support.

WriteApi supports:

  1. writing data using InfluxDB Line Protocol, Data Point, POCO
  2. use batching for writes
  3. produces events that allow user to be notified and react to this events
    • WriteSuccessEvent - published when arrived the success response from server
    • WriteErrorEvent - published when occurs a unhandled exception from server
    • WriteRetriableErrorEvent - published when occurs a retriable error from server
    • WriteRuntimeExceptionEvent - published when occurs a runtime exception in background batch processing
  4. use GZIP compression for data

The writes are processed in batches which are configurable by WriteOptions:

Property Description Default Value
BatchSize the number of data point to collect in batch 1000
FlushInterval the number of milliseconds before the batch is written 1000
JitterInterval the number of milliseconds to increase the batch flush interval by a random amount 0
RetryInterval the number of milliseconds to retry unsuccessful write. The retry interval is used when the InfluxDB server does not specify "Retry-After" header. 5000
MaxRetries the number of max retries when write fails 3
MaxRetryDelay the maximum delay between each retry attempt in milliseconds 125_000
ExponentialBase the base for the exponential retry delay, the next delay is computed using random exponential backoff as a random value within the interval retryInterval * exponentialBase^(attempts-1) and retryInterval * exponentialBase^(attempts). Example for retryInterval=5_000, exponentialBase=2, maxRetryDelay=125_000, maxRetries=5 Retry delays are random distributed values within the ranges of [5_000-10_000, 10_000-20_000, 20_000-40_000, 40_000-80_000, 80_000-125_000] 2

Writing data

By POCO

Write Measurement into specified bucket:

using System;
using InfluxDB.Client;
using InfluxDB.Client.Api.Domain;
using InfluxDB.Client.Core;

namespace Examples
{
    public static class WritePoco
    {
        private static readonly string Token = "";

        public static void Main()
        {
            using var client = new InfluxDBClient("http://localhost:8086", Token);

            //
            // Write Data
            //
            using (var writeApi = client.GetWriteApi())
            {
                //
                // Write by POCO
                //
                var temperature = new Temperature {Location = "south", Value = 62D, Time = DateTime.UtcNow};

                writeApi.WriteMeasurement(temperature, WritePrecision.Ns, "bucket_name", "org_id");
            }
        }
        
        [Measurement("temperature")]
        private class Temperature
        {
            [Column("location", IsTag = true)] public string Location { get; set; }

            [Column("value")] public double Value { get; set; }

            [Column(IsTimestamp = true)] public DateTime Time { get; set; }
        }
    }
}
By Data Point

Write Data point into specified bucket:

using System;
using InfluxDB.Client;
using InfluxDB.Client.Api.Domain;
using InfluxDB.Client.Writes;

namespace Examples
{
    public static class WriteDataPoint
    {
        private static readonly string Token = "";

        public static void Main()
        {
            using var client = new InfluxDBClient("http://localhost:8086", Token);

            //
            // Write Data
            //
            using (var writeApi = client.GetWriteApi())
            {
                //
                // Write by Data Point
                
                var point = PointData.Measurement("temperature")
                    .Tag("location", "west")
                    .Field("value", 55D)
                    .Timestamp(DateTime.UtcNow.AddSeconds(-10), WritePrecision.Ns);
                
                writeApi.WritePoint(point, "bucket_name", "org_id");
            }
        }
    }
}

DataPoint Builder Immutability: The builder is immutable therefore won't have side effect when using for building multiple point with single builder.

using System;
using InfluxDB.Client;
using InfluxDB.Client.Api.Domain;
using InfluxDB.Client.Writes;

namespace Examples
{
    public static class WriteDataPoint
    {
        private static readonly string Token = "";

        public static void Main()
        {
            using var client = new InfluxDBClient("http://localhost:8086", Token);

            //
            // Write Data
            //
            using (var writeApi = client.GetWriteApi())
            {
                //
                // Write by Data Point
                
                var builder = PointData.Measurement("temperature")
                    .Tag("location", "west");
                
                var pointA = builder
                    .Field("value", 55D)
                    .Timestamp(DateTime.UtcNow.AddSeconds(-10), WritePrecision.Ns);
                
                writeApi.WritePoint(pointA, "bucket_name", "org_id");
                
                var pointB = builder
                    .Field("age", 32)
                    .Timestamp(DateTime.UtcNow, WritePrecision.Ns);
                
                writeApi.WritePoint(pointB, "bucket_name", "org_id");
            }
        }
    }
}
By LineProtocol

Write Line Protocol record into specified bucket:

using InfluxDB.Client;
using InfluxDB.Client.Api.Domain;

namespace Examples
{
    public static class WriteLineProtocol
    {
        private static readonly string Token = "";

        public static void Main()
        {
            using var client = new InfluxDBClient("http://localhost:8086", Token);

            //
            // Write Data
            //
            using (var writeApi = client.GetWriteApi())
            {
                //
                //
                // Write by LineProtocol
                //
                writeApi.WriteRecord("temperature,location=north value=60.0", WritePrecision.Ns,"bucket_name", "org_id");
            }
        }
    }
}
Using WriteApiAsync
using System;
using System.Threading.Tasks;
using InfluxDB.Client;
using InfluxDB.Client.Api.Domain;
using InfluxDB.Client.Core;
using InfluxDB.Client.Writes;

namespace Examples
{
    public static class WriteApiAsyncExample
    {   
        [Measurement("temperature")]
        private class Temperature
        {
            [Column("location", IsTag = true)] public string Location { get; set; }

            [Column("value")] public double Value { get; set; }

            [Column(IsTimestamp = true)] public DateTime Time { get; set; }
        }
        
        public static async Task Main()
        {
            using var client = new InfluxDBClient("http://localhost:8086", 
                            "my-user", "my-password");

            //
            // Write Data
            //
            var writeApiAsync = client.GetWriteApiAsync();

            //
            //
            // Write by LineProtocol
            //
            await writeApiAsync.WriteRecordAsync("temperature,location=north value=60.0", WritePrecision.Ns,
                "my-bucket", "my-org");

            //
            //
            // Write by Data Point
            //               
            var point = PointData.Measurement("temperature")
                            .Tag("location", "west")
                            .Field("value", 55D)
                            .Timestamp(DateTime.UtcNow.AddSeconds(-10), WritePrecision.Ns);

            await writeApiAsync.WritePointAsync(point, "my-bucket", "my-org");

            //
            // Write by POCO
            //
            var temperature = new Temperature {Location = "south", Value = 62D, Time = DateTime.UtcNow};

            await writeApiAsync.WriteMeasurementAsync(temperature, WritePrecision.Ns, "my-bucket", "my-org");

            //
            // Check written data
            //
            var tables = await influxDbClient.GetQueryApi()
                            .QueryAsync("from(bucket:\"my-bucket\") |> range(start: 0)", "my-org");
            
            tables.ForEach(table =>
            {
                var fluxRecords = table.Records;
                fluxRecords.ForEach(record =>
                {
                    Console.WriteLine($"{record.GetTime()}: {record.GetValue()}");
                });
            });
        }
    }
}
Default Tags

Sometimes is useful to store same information in every measurement e.g. hostname, location, customer. The client is able to use static value, app settings or env variable as a tag value.

The expressions:

  • California Miner - static value
  • ${version} - application settings
  • ${env.hostname} - environment property
Via Configuration file

In a configuration file you are able to specify default tags by tags element.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <section name="influx2" type="InfluxDB.Client.Configurations.Influx2, InfluxDB.Client" />
    </configSections>
    <appSettings>
        <add key="SensorVersion" value="v1.00"/>
    </appSettings>
    <influx2 url="http://localhost:8086"
             org="my-org"
             bucket="my-bucket"
             token="my-token"
             logLevel="BODY"
             timeout="10s">
        <tags>
            <tag name="id" value="132-987-655"/>
            <tag name="customer" value="California Miner"/>
            <tag name="hostname" value="${env.Hostname}"/>
            <tag name="sensor-version" value="${SensorVersion}"/>
        </tags>
    </influx2>
</configuration>
Via API
var options = new InfluxDBClientOptions(Url)
{
    Token = token,
    DefaultTags = new Dictionary<string, string>
    {
        {"id", "132-987-655"},
        {"customer", "California Miner"},
    }
};   
options.AddDefaultTag("hostname", "${env.Hostname}")
options.AddDefaultTags(new Dictionary<string, string>{{ "sensor-version", "${SensorVersion}" }})

Both of configurations will produce the Line protocol:

mine-sensor,id=132-987-655,customer="California Miner",hostname=example.com,sensor-version=v1.00 altitude=10

Handle the Events

Events that can be handle by WriteAPI EventHandler are:

  • WriteSuccessEvent - for success response from server
  • WriteErrorEvent - for unhandled exception from server
  • WriteRetriableErrorEvent - for retriable error from server
  • WriteRuntimeExceptionEvent - for runtime exception in background batch processing

Number of events depends on number of data points to collect in batch. The batch size is configured by BatchSize option (default size is 1000) - in case of one data point, event is handled for each point, independently on used writing method (even for mass writing of data like WriteMeasurements, WritePoints and WriteRecords).

Events can be handled by register writeApi.EventHandler or by creating custom EventListener:

Register EventHandler
writeApi.EventHandler += (sender, eventArgs) =>
{
    switch (eventArgs)
    {
        case WriteSuccessEvent successEvent:
            string data = @event.LineProtocol;
            //
            // handle success response from server
            // Console.WriteLine($"{data}");
            //
            break;
        case WriteErrorEvent error:
            string data = @error.LineProtocol;
            string errorMessage = @error.Exception.Message;
            //
            // handle unhandled exception from server
            //
            // Console.WriteLine($"{data}");
            // throw new Exception(errorMessage);
            //
            break;
        case WriteRetriableErrorEvent error:
            string data = @error.LineProtocol;
            string errorMessage = @error.Exception.Message;
            //
            // handle retrievable error from server
            //
            // Console.WriteLine($"{data}");
            // throw new Exception(errorMessage);
            //
            break;
        case WriteRuntimeExceptionEvent error:
            string errorMessage = @error.Exception.Message;
            //
            // handle runtime exception in background batch processing
            // throw new Exception(errorMessage);
            //
            break;
    }
};

//
// Write by LineProtocol
//
writeApi.WriteRecord("influxPoint,writeType=lineProtocol value=11.11" +
    $" {DateTime.UtcNow.Subtract(EpochStart).Ticks * 100}", WritePrecision.Ns, "my-bucket", "my-org");
Custom EventListener

Advantage of using custom Event Listener is possibility of waiting on handled event between different writings - for more info see EventListener.

Delete Data

Delete data from specified bucket:

using InfluxDB.Client;
using InfluxDB.Client.Api.Domain;

namespace Examples
{
    public static class WriteLineProtocol
    {
        private static readonly string Token = "";

        public static void Main()
        {
            using var client = new InfluxDBClient("http://localhost:8086", Token);

            //
            // Delete data
            //
            await client.GetDeleteApi().Delete(DateTime.UtcNow.AddMinutes(-1), DateTime.Now, "", "bucket", "org");
        }
    }
}

Filter trace verbose

You can filter out verbose messages from InfluxDB.Client by using TraceListener.

using System;
using System.Diagnostics;
using InfluxDB.Client.Core;

namespace Examples
{
  public static class MyProgram
  {
    public static void Main()
    {
      TraceListener ConsoleOutListener = new TextWriterTraceListener(Console.Out)
      {
        Filter = InfluxDBTraceFilter.SuppressInfluxVerbose(),
      };
      Trace.Listeners.Add(ConsoleOutListener);

      // My code ...
    }
  }
}

Management API

The client has following management API:

API endpoint Description Implementation
/api/v2/authorizations Managing authorization data AuthorizationsApi
/api/v2/buckets Managing bucket data BucketsApi
/api/v2/orgs Managing organization data OrganizationsApi
/api/v2/users Managing user data UsersApi
/api/v2/sources Managing sources SourcesApi
/api/v2/tasks Managing one-off and recurring tasks TasksApi
/api/v2/scrapers Managing ScraperTarget data ScraperTargetsApi
/api/v2/labels Managing resource labels LabelsApi
/api/v2/telegrafs Managing telegraf config data TelegrafsApi
/api/v2/setup Managing onboarding setup InfluxDBClient#OnBoarding()
/ready Get the readiness of a instance at startup InfluxDBClient#Ready()
/health Get the health of an instance anytime during execution InfluxDBClient#Health()

The following example demonstrates how to use a InfluxDB 2.x Management API. For further information see endpoints implementation.

using System;
using System.Collections.Generic;
using System.Linq;
using InfluxDB.Client;
using InfluxDB.Client.Api.Domain;
using Task = System.Threading.Tasks.Task;

namespace Examples
{
    public static class ManagementExample
    {
        public static async Task Main()
        {
            const string url = "http://localhost:8086";
            const string token = "my-token";
            const string org = "my-org";
            
            using var client = new InfluxDBClient(url, token);

            // Find ID of Organization with specified name (PermissionAPI requires ID of Organization).
            var orgId = (await client.GetOrganizationsApi().FindOrganizationsAsync(org: org)).First().Id;

            //
            // Create bucket "iot_bucket" with data retention set to 3,600 seconds
            //
            var retention = new BucketRetentionRules(BucketRetentionRules.TypeEnum.Expire, 3600);

            var bucket = await client.GetBucketsApi().CreateBucketAsync("iot_bucket", retention, orgId);

            //
            // Create access token to "iot_bucket"
            //
            var resource = new PermissionResource(PermissionResource.TypeBuckets, bucket.Id, null,
                orgId);

            // Read permission
            var read = new Permission(Permission.ActionEnum.Read, resource);

            // Write permission
            var write = new Permission(Permission.ActionEnum.Write, resource);

            var authorization = await client.GetAuthorizationsApi()
                .CreateAuthorizationAsync(orgId, new List<Permission> { read, write });

            //
            // Created token that can be use for writes to "iot_bucket"
            //
            Console.WriteLine($"Authorized token to write into iot_bucket: {authorization.Token}");
        }
    }
}

If there is no API implementation for particular service you could create the service by:

var dbrpService = _client.CreateService<DBRPsService>(typeof(DBRPsService));

Advanced Usage

Monitoring & Alerting

The example below show how to create a check for monitoring a stock price. A Slack notification is created if the price is lesser than 35.

Create Threshold Check

The Check set status to Critical if the current value for a stock measurement is lesser than 35.

var org = ...;

var query = "from(bucket: \"my-bucket\") "
        + "|> range(start: v.timeRangeStart, stop: v.timeRangeStop)  "
        + "|> filter(fn: (r) => r._measurement == \"stock\")  "
        + "|> filter(fn: (r) => r.company == \"zyz\")  "
        + "|> aggregateWindow(every: 5s, fn: mean)  "
        + "|> filter(fn: (r) => r._field == \"current\")  "
        + "|> yield(name: \"mean\")";

var threshold = new LesserThreshold(value: 35F, level: CheckStatusLevel.CRIT,
                type: LesserThreshold.TypeEnum.Lesser);

var message = "The Stock price for XYZ is on: ${ r._level } level!";

await Client
    .GetChecksApi()
    .CreateThresholdCheckAsync("XYZ Stock value", query, "5s", message, threshold, org.Id);
Create Slack Notification endpoint
var url = "https://hooks.slack.com/services/x/y/z"; 

var endpoint = await Client
    .GetNotificationEndpointsApi()
    .CreateSlackEndpointAsync("Slack Endpoint", url, org.Id);
Create Notification Rule
await Client
    .GetNotificationRulesApi()
    .CreateSlackRuleAsync("Critical status to Slack", "10s", "${ r._message }", RuleStatusLevel.CRIT, endpoint, org.Id);

Custom mapping of DomainObject to/from InfluxDB

The default mapper uses Column attributes to define how the DomainObject will be mapped to and from the InfluxDB. The our APIs also allow to specify custom mapper. For more information see following example:

using System;
using System.Threading.Tasks;
using InfluxDB.Client;
using InfluxDB.Client.Api.Domain;
using InfluxDB.Client.Core.Flux.Domain;
using InfluxDB.Client.Writes;

namespace Examples
{
    public static class CustomDomainMapping
    {
        /// <summary>
        /// Define Domain Object
        /// </summary>
        private class Sensor
        {
            /// <summary>
            /// Type of sensor.
            /// </summary>
            public String Type { get; set; }
            
            /// <summary>
            /// Version of sensor.
            /// </summary>
            public String Version { get; set; }

            /// <summary>
            /// Measured value.
            /// </summary>
            public double Value { get; set; }

            public DateTimeOffset Timestamp { get; set; }

            public override string ToString()
            {
                return $"{Timestamp:MM/dd/yyyy hh:mm:ss.fff tt} {Type}, {Version} value: {Value}";
            }
        }

        /// <summary>
        /// Define Custom Domain Object Converter
        /// </summary>
        private class DomainEntityConverter : IDomainObjectMapper
        {
            /// <summary>
            /// Convert to DomainObject.
            /// </summary>
            public object ConvertToEntity(FluxRecord fluxRecord, Type type)
            {
                if (type != typeof(Sensor))
                {
                    throw new NotSupportedException($"This converter doesn't supports: {type}");
                }

                var customEntity = new Sensor
                {
                    Type = Convert.ToString(fluxRecord.GetValueByKey("type")),
                    Version = Convert.ToString(fluxRecord.GetValueByKey("version")),
                    Value = Convert.ToDouble(fluxRecord.GetValueByKey("data")),
                    Timestamp = fluxRecord.GetTime().GetValueOrDefault().ToDateTimeUtc(),
                };
                
                return Convert.ChangeType(customEntity, type);
            }
            
            /// <summary>
            /// Convert to DomainObject.
            /// </summary>
            public T ConvertToEntity<T>(FluxRecord fluxRecord)
            {
                return (T)ConvertToEntity(fluxRecord, typeof(T));
            }

            /// <summary>
            /// Convert to Point
            /// </summary>
            public PointData ConvertToPointData<T>(T entity, WritePrecision precision)
            {
                if (!(entity is Sensor sensor))
                {
                    throw new NotSupportedException($"This converter doesn't supports: {entity}");
                }

                var point = PointData
                    .Measurement("sensor")
                    .Tag("type", sensor.Type)
                    .Tag("version", sensor.Version)
                    .Field("data", sensor.Value)
                    .Timestamp(sensor.Timestamp, precision);

                return point;
            }
        }

        public static async Task Main(string[] args)
        {
            const string host = "http://localhost:9999";
            const string token = "my-token";
            const string bucket = "my-bucket";
            const string organization = "my-org";
            var options = new InfluxDBClientOptions(host)
            {
                Token = token,
                Org = organization,
                Bucket = bucket
            };

            var converter = new DomainEntityConverter();
            using var client = new InfluxDBClient(options);

            //
            // Prepare data to write
            //
            var time = new DateTimeOffset(2020, 11, 15, 8, 20, 15,
                new TimeSpan(3, 0, 0));

            var entity1 = new Sensor
            {
                Timestamp = time,
                Type = "temperature",
                Version = "v0.0.2",
                Value = 15
            };
            var entity2 = new Sensor
            {
                Timestamp = time.AddHours(1),
                Type = "temperature",
                Version = "v0.0.2",
                Value = 15
            };
            var entity3 = new Sensor
            {
                Timestamp = time.AddHours(2),
                Type = "humidity",
                Version = "v0.13",
                Value = 74
            };
            var entity4 = new Sensor
            {
                Timestamp = time.AddHours(3),
                Type = "humidity",
                Version = "v0.13",
                Value = 82
            };

            //
            // Write data
            //
            await client.GetWriteApiAsync(converter)
                .WriteMeasurementsAsync(new []{entity1, entity2, entity3, entity4}, WritePrecision.S);

            //
            // Query Data to Domain object
            //
            var queryApi = client.GetQueryApiSync(converter);

            //
            // Select ALL
            //
            var query = $"from(bucket:\"{bucket}\") " +
                        "|> range(start: 0) " +
                        "|> filter(fn: (r) => r[\"_measurement\"] == \"sensor\")" +
                        "|> pivot(rowKey:[\"_time\"], columnKey: [\"_field\"], valueColumn: \"_value\")";
           
            var sensors = queryApi.QuerySync<Sensor>(query);
            //
            // Print result
            //
            sensors.ForEach(it => Console.WriteLine(it.ToString()));
        }
    }
}

Client configuration file

A client can be configured via App.config file.

The following options are supported:

Property name default description
Url - the url to connect to InfluxDB
Org - default destination organization for writes and queries
Bucket - default destination bucket for writes
Token - the token to use for the authorization
LogLevel NONE rest client verbosity level
Timeout 10000 ms The timespan to wait before the HTTP request times out
AllowHttpRedirects false Configure automatically following HTTP 3xx redirects
VerifySsl true Ignore Certificate Validation Errors when false

The Timeout supports ms, s and m as unit. Default is milliseconds.

Configuration example
<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <section name="influx2" type="InfluxDB.Client.Configurations.Influx2, InfluxDB.Client" />
    </configSections>

    <influx2 url="http://localhost:8086"
             org="my-org"
             bucket="my-bucket"
             token="my-token"
             logLevel="BODY"
             timeout="10s">
    </influx2>
</configuration>

and then:

var client = InfluxDBClientFactory.Create();

Client connection string

A client can be constructed using a connection string that can contain the InfluxDBClientOptions parameters encoded into the URL.

var client = new InfluxDBClient("http://localhost:8086?timeout=5000&logLevel=BASIC");

The following options are supported:

Property name default description
org - default destination organization for writes and queries
bucket - default destination bucket for writes
token - the token to use for the authorization
logLevel NONE rest client verbosity level
timeout 10000 ms The timespan to wait before the HTTP request times out.
allowHttpRedirects false Configure automatically following HTTP 3xx redirects
verifySsl true Ignore Certificate Validation Errors when false

The timeout supports ms, s and m as unit. Default is milliseconds.

Gzip support

InfluxDBClient does not enable gzip compress for http requests by default. If you want to enable gzip to reduce transfer data's size, you can call:

influxDBClient.EnableGzip();

How to use WebProxy

You can configure the client to tunnel requests through an HTTP proxy. The WebProxy could be configured via InfluxDBClientOptions parameter WebProxy:

var options = new InfluxDBClientOptions("http://localhost:8086")
{
    Token = "my-token",
    WebProxy = new WebProxy("http://proxyserver:80/", true)
};

var client = new InfluxDBClient(options);

Redirects configuration

Client automatically doesn't follows HTTP redirects. You can enable redirects by AllowRedirects configuration option:

var options = new InfluxDBClientOptions("http://localhost:8086")
{
    Token = "my-token",
    AllowRedirects = true
};

using var client = new InfluxDBClient(options);

⚠️ Due to a security reason Authorization header is not forwarded when redirect leads to a different domain. You can create custom Authenticator which change this behaviour - see more.

Log HTTP Request and Response

The Requests and Responses can be logged by changing the LogLevel. LogLevel values are None, Basic, Headers, Body. Note that applying the Body LogLevel will disable chunking while streaming and will load the whole response into memory.

client.SetLogLevel(LogLevel.Body)
Check the server status and version

Server availability can be checked using the influxDBClient.PingAsync() endpoint.

Version

The latest package for .NET CLI:

dotnet add package InfluxDB.Client

Or when using with Package Manager:

Install-Package InfluxDB.Client
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 is compatible. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (29)

Showing the top 5 NuGet packages that depend on InfluxDB.Client:

Package Downloads
InfluxDB.Client.Linq

The library supports querying InfluxDB 2.x by LINQ expressions.

AWF.Fabric

基础结构模块,提供框架级支持

NBomber.Sinks.InfluxDB

NBomber sink that writes stats data to InfluxDB.

Serilog.Sinks.InfluxDB.Syslog

InfluxDB sink for Serilog with .NET standard 2.0 using syslog format for Influx 2.X

IoTSharp.HealthChecks.InfluxDB

HealthChecks.InfluxDB is the health check package for InfluxDB.

GitHub repositories (8)

Showing the top 5 popular GitHub repositories that depend on InfluxDB.Client:

Repository Stars
Xabaril/AspNetCore.Diagnostics.HealthChecks
Enterprise HealthChecks for ASP.NET Core Diagnostics Package
testcontainers/testcontainers-dotnet
A library to support tests with throwaway instances of Docker containers for all compatible .NET Standard versions.
IoTSharp/IoTSharp
IoTSharp is an open-source IoT platform for data collection, processing, visualization, and device management.
ConcreteMC/Alex
A Minecraft client written in C# aimed at compatibility with MC:Java & MC:Bedrock
melanchall/drywetmidi
.NET library to read, write, process MIDI files and to work with MIDI devices
Version Downloads Last updated
4.17.0-dev.14044 58 6/24/2024
4.16.0 1,077 6/24/2024
4.16.0-dev.13990 331 6/3/2024
4.16.0-dev.13973 36 6/3/2024
4.16.0-dev.13972 39 6/3/2024
4.16.0-dev.13963 47 6/3/2024
4.16.0-dev.13962 42 6/3/2024
4.16.0-dev.13881 41 6/3/2024
4.16.0-dev.13775 123 5/17/2024
4.16.0-dev.13702 53 5/17/2024
4.15.0 14,830 5/17/2024
4.15.0-dev.13674 60 5/14/2024
4.15.0-dev.13567 495 4/2/2024
4.15.0-dev.13558 49 4/2/2024
4.15.0-dev.13525 48 4/2/2024
4.15.0-dev.13524 44 4/2/2024
4.15.0-dev.13433 178 3/7/2024
4.15.0-dev.13432 49 3/7/2024
4.15.0-dev.13407 85 3/7/2024
4.15.0-dev.13390 47 3/7/2024
4.15.0-dev.13388 45 3/7/2024
4.15.0-dev.13282 239 3/6/2024
4.15.0-dev.13257 59 3/6/2024
4.15.0-dev.13113 1,095 2/1/2024
4.15.0-dev.13104 53 2/1/2024
4.15.0-dev.13081 52 2/1/2024
4.15.0-dev.13040 109 2/1/2024
4.15.0-dev.13039 46 2/1/2024
4.15.0-dev.12863 2,056 1/8/2024
4.15.0-dev.12846 61 1/8/2024
4.15.0-dev.12837 57 1/8/2024
4.15.0-dev.12726 2,447 12/1/2023
4.15.0-dev.12725 62 12/1/2023
4.15.0-dev.12724 60 12/1/2023
4.15.0-dev.12691 64 12/1/2023
4.15.0-dev.12658 70 12/1/2023
4.15.0-dev.12649 63 12/1/2023
4.15.0-dev.12624 60 12/1/2023
4.15.0-dev.12471 881 11/7/2023
4.15.0-dev.12462 60 11/7/2023
4.14.0 288,512 11/7/2023
4.14.0-dev.12437 60 11/7/2023
4.14.0-dev.12343 104 11/2/2023
4.14.0-dev.12310 61 11/2/2023
4.14.0-dev.12284 337 11/1/2023
4.14.0-dev.12235 82 11/1/2023
4.14.0-dev.12226 67 11/1/2023
4.14.0-dev.11972 4,801 8/8/2023
4.14.0-dev.11915 123 7/31/2023
4.14.0-dev.11879 144 7/28/2023
4.13.0 232,422 7/28/2023
4.13.0-dev.11854 89 7/28/2023
4.13.0-dev.11814 343 7/21/2023
4.13.0-dev.11771 130 7/19/2023
4.13.0-dev.11770 89 7/19/2023
4.13.0-dev.11728 114 7/18/2023
4.13.0-dev.11686 184 7/17/2023
4.13.0-dev.11685 80 7/17/2023
4.13.0-dev.11676 89 7/17/2023
4.13.0-dev.11479 1,657 6/27/2023
4.13.0-dev.11478 84 6/27/2023
4.13.0-dev.11477 88 6/27/2023
4.13.0-dev.11396 438 6/19/2023
4.13.0-dev.11395 82 6/19/2023
4.13.0-dev.11342 331 6/15/2023
4.13.0-dev.11330 261 6/12/2023
4.13.0-dev.11305 87 6/12/2023
4.13.0-dev.11296 87 6/12/2023
4.13.0-dev.11217 356 6/6/2023
4.13.0-dev.11089 280 5/30/2023
4.13.0-dev.11064 109 5/30/2023
4.13.0-dev.10998 148 5/29/2023
4.13.0-dev.10989 100 5/29/2023
4.13.0-dev.10871 840 5/8/2023
4.13.0-dev.10870 79 5/8/2023
4.13.0-dev.10819 262 4/28/2023
4.12.0 148,379 4/28/2023
4.12.0-dev.10777 117 4/27/2023
4.12.0-dev.10768 104 4/27/2023
4.12.0-dev.10759 98 4/27/2023
4.12.0-dev.10742 81 4/27/2023
4.12.0-dev.10685 92 4/27/2023
4.12.0-dev.10684 88 4/27/2023
4.12.0-dev.10643 96 4/27/2023
4.12.0-dev.10642 87 4/27/2023
4.12.0-dev.10569 88 4/27/2023
4.12.0-dev.10193 1,724 2/23/2023
4.11.0 102,687 2/23/2023
4.11.0-dev.10176 162 2/23/2023
4.11.0-dev.10059 2,807 1/26/2023
4.10.0 65,661 1/26/2023
4.10.0-dev.10033 135 1/25/2023
4.10.0-dev.10032 106 1/25/2023
4.10.0-dev.10031 119 1/25/2023
4.10.0-dev.9936 3,443 12/26/2022
4.10.0-dev.9935 124 12/26/2022
4.10.0-dev.9881 168 12/21/2022
4.10.0-dev.9880 104 12/21/2022
4.10.0-dev.9818 601 12/16/2022
4.10.0-dev.9773 250 12/12/2022
4.10.0-dev.9756 101 12/12/2022
4.10.0-dev.9693 350 12/6/2022
4.9.0 156,954 12/6/2022
4.9.0-dev.9684 101 12/6/2022
4.9.0-dev.9666 108 12/6/2022
4.9.0-dev.9617 120 12/6/2022
4.9.0-dev.9478 187 12/5/2022
4.9.0-dev.9469 120 12/5/2022
4.9.0-dev.9444 93 12/5/2022
4.9.0-dev.9411 107 12/5/2022
4.9.0-dev.9350 149 12/1/2022
4.8.0 5,155 12/1/2022
4.8.0-dev.9324 186 11/30/2022
4.8.0-dev.9232 173 11/28/2022
4.8.0-dev.9223 105 11/28/2022
4.8.0-dev.9222 107 11/28/2022
4.8.0-dev.9117 388 11/21/2022
4.8.0-dev.9108 113 11/21/2022
4.8.0-dev.9099 113 11/21/2022
4.8.0-dev.9029 185 11/16/2022
4.8.0-dev.8971 115 11/15/2022
4.8.0-dev.8961 119 11/14/2022
4.8.0-dev.8928 119 11/14/2022
4.8.0-dev.8899 116 11/14/2022
4.8.0-dev.8898 126 11/14/2022
4.8.0-dev.8839 116 11/14/2022
4.8.0-dev.8740 234 11/7/2022
4.8.0-dev.8725 105 11/7/2022
4.8.0-dev.8648 353 11/3/2022
4.7.0 94,453 11/3/2022
4.7.0-dev.8625 259 11/2/2022
4.7.0-dev.8594 264 10/31/2022
4.7.0-dev.8579 109 10/31/2022
4.7.0-dev.8557 99 10/31/2022
4.7.0-dev.8540 111 10/31/2022
4.7.0-dev.8518 110 10/31/2022
4.7.0-dev.8517 109 10/31/2022
4.7.0-dev.8509 102 10/31/2022
4.7.0-dev.8377 799 10/26/2022
4.7.0-dev.8360 124 10/25/2022
4.7.0-dev.8350 158 10/24/2022
4.7.0-dev.8335 115 10/24/2022
4.7.0-dev.8334 112 10/24/2022
4.7.0-dev.8223 212 10/19/2022
4.7.0-dev.8178 227 10/17/2022
4.7.0-dev.8170 113 10/17/2022
4.7.0-dev.8148 119 10/17/2022
4.7.0-dev.8133 109 10/17/2022
4.7.0-dev.8097 102 10/17/2022
4.7.0-dev.8034 928 10/11/2022
4.7.0-dev.8025 126 10/11/2022
4.7.0-dev.8009 183 10/10/2022
4.7.0-dev.8001 125 10/10/2022
4.7.0-dev.7959 194 10/4/2022
4.7.0-dev.7905 314 9/30/2022
4.7.0-dev.7875 159 9/29/2022
4.6.0 45,711 9/29/2022
4.6.0-dev.7832 159 9/29/2022
4.6.0-dev.7817 117 9/29/2022
4.6.0-dev.7779 183 9/27/2022
4.6.0-dev.7778 130 9/27/2022
4.6.0-dev.7734 146 9/26/2022
4.6.0-dev.7733 120 9/26/2022
4.6.0-dev.7677 222 9/20/2022
4.6.0-dev.7650 214 9/16/2022
4.6.0-dev.7626 193 9/14/2022
4.6.0-dev.7618 175 9/14/2022
4.6.0-dev.7574 116 9/13/2022
4.6.0-dev.7572 107 9/13/2022
4.6.0-dev.7528 251 9/12/2022
4.6.0-dev.7502 152 9/9/2022
4.6.0-dev.7479 182 9/8/2022
4.6.0-dev.7471 127 9/8/2022
4.6.0-dev.7447 175 9/7/2022
4.6.0-dev.7425 114 9/7/2022
4.6.0-dev.7395 140 9/6/2022
4.6.0-dev.7344 319 8/31/2022
4.6.0-dev.7329 106 8/31/2022
4.6.0-dev.7292 116 8/30/2022
4.6.0-dev.7240 301 8/29/2022
4.5.0 56,849 8/29/2022
4.5.0-dev.7216 136 8/27/2022
4.5.0-dev.7147 295 8/22/2022
4.5.0-dev.7134 326 8/17/2022
4.5.0-dev.7096 165 8/15/2022
4.5.0-dev.7070 258 8/11/2022
4.5.0-dev.7040 175 8/10/2022
4.5.0-dev.7011 229 8/3/2022
4.5.0-dev.6987 131 8/1/2022
4.5.0-dev.6962 142 7/29/2022
4.4.0 48,110 7/29/2022
4.4.0-dev.6901 329 7/25/2022
4.4.0-dev.6843 364 7/19/2022
4.4.0-dev.6804 129 7/19/2022
4.4.0-dev.6789 121 7/19/2022
4.4.0-dev.6760 125 7/19/2022
4.4.0-dev.6705 209 7/14/2022
4.4.0-dev.6663 1,106 6/24/2022
4.4.0-dev.6655 140 6/24/2022
4.3.0 148,369 6/24/2022
4.3.0-dev.multiple.buckets3 277 6/21/2022
4.3.0-dev.multiple.buckets2 251 6/17/2022
4.3.0-dev.multiple.buckets1 126 6/17/2022
4.3.0-dev.6631 131 6/22/2022
4.3.0-dev.6623 122 6/22/2022
4.3.0-dev.6374 448 6/13/2022
4.3.0-dev.6286 980 5/20/2022
4.2.0 66,169 5/20/2022
4.2.0-dev.6257 601 5/13/2022
4.2.0-dev.6248 133 5/12/2022
4.2.0-dev.6233 228 5/12/2022
4.2.0-dev.6194 235 5/10/2022
4.2.0-dev.6193 144 5/10/2022
4.2.0-dev.6158 3,040 5/6/2022
4.2.0-dev.6135 185 5/6/2022
4.2.0-dev.6091 515 4/28/2022
4.2.0-dev.6048 160 4/28/2022
4.2.0-dev.6047 133 4/28/2022
4.2.0-dev.5966 484 4/25/2022
4.2.0-dev.5938 379 4/19/2022
4.1.0 45,479 4/19/2022
4.1.0-dev.5910 346 4/13/2022
4.1.0-dev.5888 140 4/13/2022
4.1.0-dev.5887 147 4/13/2022
4.1.0-dev.5794 845 4/6/2022
4.1.0-dev.5725 459 3/18/2022
4.0.0 57,237 3/18/2022
4.0.0-rc3 945 3/4/2022
4.0.0-rc2 668 2/25/2022
4.0.0-rc1 2,159 2/18/2022
4.0.0-dev.5709 139 3/18/2022
4.0.0-dev.5684 157 3/15/2022
4.0.0-dev.5630 135 3/4/2022
4.0.0-dev.5607 146 3/3/2022
4.0.0-dev.5579 157 2/25/2022
4.0.0-dev.5556 150 2/24/2022
4.0.0-dev.5555 144 2/24/2022
4.0.0-dev.5497 157 2/23/2022
4.0.0-dev.5489 143 2/23/2022
4.0.0-dev.5460 150 2/23/2022
4.0.0-dev.5444 153 2/22/2022
4.0.0-dev.5333 163 2/17/2022
4.0.0-dev.5303 160 2/16/2022
4.0.0-dev.5280 149 2/16/2022
4.0.0-dev.5279 153 2/16/2022
4.0.0-dev.5241 332 2/15/2022
4.0.0-dev.5225 155 2/15/2022
4.0.0-dev.5217 143 2/15/2022
4.0.0-dev.5209 139 2/15/2022
4.0.0-dev.5200 154 2/14/2022
4.0.0-dev.5188 700 2/10/2022
4.0.0-dev.5180 370 2/10/2022
4.0.0-dev.5172 364 2/10/2022
4.0.0-dev.5130 372 2/10/2022
4.0.0-dev.5122 381 2/9/2022
4.0.0-dev.5103 379 2/9/2022
4.0.0-dev.5097 378 2/9/2022
4.0.0-dev.5091 362 2/9/2022
4.0.0-dev.5084 358 2/8/2022
3.4.0-dev.5263 151 2/15/2022
3.4.0-dev.4986 391 2/7/2022
3.4.0-dev.4968 420 2/4/2022
3.3.0 127,548 2/4/2022
3.3.0-dev.4889 408 2/3/2022
3.3.0-dev.4865 403 2/1/2022
3.3.0-dev.4823 323 1/19/2022
3.3.0-dev.4691 901 1/7/2022
3.3.0-dev.4557 2,203 11/26/2021
3.2.0 92,263 11/26/2021
3.2.0-dev.4533 5,067 11/24/2021
3.2.0-dev.4484 354 11/11/2021
3.2.0-dev.4475 214 11/10/2021
3.2.0-dev.4387 278 10/26/2021
3.2.0-dev.4363 242 10/22/2021
3.2.0-dev.4356 188 10/22/2021
3.1.0 91,035 10/22/2021
3.1.0-dev.4303 436 10/18/2021
3.1.0-dev.4293 212 10/15/2021
3.1.0-dev.4286 191 10/15/2021
3.1.0-dev.4240 253 10/12/2021
3.1.0-dev.4202 209 10/11/2021
3.1.0-dev.4183 214 10/11/2021
3.1.0-dev.4131 193 10/8/2021
3.1.0-dev.3999 209 10/5/2021
3.1.0-dev.3841 323 9/29/2021
3.1.0-dev.3798 406 9/17/2021
3.0.0 58,356 9/17/2021
3.0.0-dev.3726 2,533 8/31/2021
3.0.0-dev.3719 167 8/31/2021
3.0.0-dev.3671 397 8/20/2021
2.2.0-dev.3652 168 8/20/2021
2.1.0 243,860 8/20/2021
2.1.0-dev.3605 216 8/17/2021
2.1.0-dev.3584 529 8/16/2021
2.1.0-dev.3558 176 8/16/2021
2.1.0-dev.3527 320 7/29/2021
2.1.0-dev.3519 234 7/29/2021
2.1.0-dev.3490 305 7/20/2021
2.1.0-dev.3445 265 7/12/2021
2.1.0-dev.3434 243 7/9/2021
2.0.0 62,755 7/9/2021
2.0.0-dev.3401 7,052 6/25/2021
2.0.0-dev.3368 251 6/23/2021
2.0.0-dev.3361 222 6/23/2021
2.0.0-dev.3330 256 6/17/2021
2.0.0-dev.3291 243 6/16/2021
1.20.0-dev.3218 520 6/4/2021
1.19.0 117,440 6/4/2021
1.19.0-dev.3204 219 6/3/2021
1.19.0-dev.3160 209 6/2/2021
1.19.0-dev.3159 181 6/2/2021
1.19.0-dev.3084 2,496 5/7/2021
1.19.0-dev.3051 260 5/5/2021
1.19.0-dev.3044 208 5/5/2021
1.19.0-dev.3008 243 4/30/2021
1.18.0 35,804 4/30/2021
1.18.0-dev.2973 231 4/27/2021
1.18.0-dev.2930 1,188 4/16/2021
1.18.0-dev.2919 228 4/13/2021
1.18.0-dev.2893 228 4/12/2021
1.18.0-dev.2880 202 4/12/2021
1.18.0-dev.2856 232 4/7/2021
1.18.0-dev.2830 1,827 4/1/2021
1.18.0-dev.2816 190 4/1/2021
1.17.0 44,967 4/1/2021
1.17.0-dev.linq.17 873 3/18/2021
1.17.0-dev.linq.16 240 3/16/2021
1.17.0-dev.linq.15 220 3/15/2021
1.17.0-dev.linq.14 235 3/12/2021
1.17.0-dev.linq.13 273 3/11/2021
1.17.0-dev.linq.12 200 3/10/2021
1.17.0-dev.linq.11 238 3/8/2021
1.17.0-dev.2776 216 3/26/2021
1.17.0-dev.2713 183 3/25/2021
1.17.0-dev.2707 181 3/25/2021
1.17.0-dev.2652 243 3/19/2021
1.17.0-dev.2619 183 3/18/2021
1.17.0-dev.2566 184 3/16/2021
1.17.0-dev.2549 187 3/15/2021
1.17.0-dev.2505 227 3/12/2021
1.17.0-dev.2446 212 3/11/2021
1.17.0-dev.2402 204 3/8/2021
1.17.0-dev.2371 203 3/5/2021
1.16.0 19,002 3/5/2021
1.16.0-dev.linq.10 1,633 2/4/2021
1.16.0-dev.linq.9 225 2/4/2021
1.16.0-dev.2359 232 3/4/2021
1.16.0-dev.2273 200 2/12/2021
1.16.0-dev.2255 198 2/11/2021
1.16.0-dev.2228 205 2/5/2021
1.16.0-dev.2147 246 1/29/2021
1.15.0 31,380 1/29/2021
1.15.0-dev.linq.8 210 1/28/2021
1.15.0-dev.linq.7 200 1/27/2021
1.15.0-dev.linq.6 266 1/20/2021
1.15.0-dev.linq.5 243 1/19/2021
1.15.0-dev.linq.4 378 1/15/2021
1.15.0-dev.linq.3 197 1/14/2021
1.15.0-dev.linq.2 206 1/13/2021
1.15.0-dev.linq.1 222 1/12/2021
1.15.0-dev.2135 196 1/28/2021
1.15.0-dev.2009 204 1/19/2021
1.15.0-dev.1793 211 1/11/2021
1.15.0-dev.1753 255 1/7/2021
1.15.0-dev.1752 243 1/7/2021
1.15.0-dev.1705 862 12/16/2020
1.15.0-dev.1677 566 12/4/2020
1.14.0 45,207 12/4/2020
1.14.0-dev.1665 259 12/3/2020
1.14.0-dev.1648 251 12/2/2020
1.14.0-dev.1632 312 11/27/2020
1.14.0-dev.1577 455 10/30/2020
1.14.0-dev.1571 311 10/30/2020
1.13.0 14,870 10/30/2020
1.13.0-dev.1545 402 10/15/2020
1.13.0-dev.1516 468 10/8/2020
1.13.0-dev.1489 571 10/2/2020
1.13.0-dev.1478 302 10/2/2020
1.12.0 34,761 10/2/2020
1.12.0-dev.1466 247 10/1/2020
1.12.0-dev.1421 549 9/23/2020
1.12.0-dev.1345 320 9/18/2020
1.12.0-dev.1306 315 9/15/2020
1.12.0-dev.1251 334 9/2/2020
1.12.0-dev.1216 1,939 8/14/2020
1.11.0 24,075 8/14/2020
1.11.0-dev.1205 285 8/14/2020
1.11.0-dev.1185 289 8/10/2020
1.11.0-dev.1166 344 7/28/2020
1.11.0-dev.1150 284 7/28/2020
1.11.0-dev.1144 303 7/28/2020
1.11.0-dev.1125 281 7/20/2020
1.11.0-dev.1111 286 7/17/2020
1.10.0 16,980 7/17/2020
1.10.0-dev.1098 267 7/15/2020
1.10.0-dev.1077 385 7/10/2020
1.10.0-dev.1049 398 6/29/2020
1.10.0-dev.1022 311 6/23/2020
1.10.0-dev.1021 301 6/23/2020
1.10.0-dev.990 296 6/19/2020
1.9.0 18,159 6/19/2020
1.9.0-dev.984 317 6/19/2020
1.9.0-dev.971 268 6/17/2020
1.9.0-dev.955 278 6/17/2020
1.9.0-dev.886 293 6/10/2020
1.9.0-dev.848 313 6/8/2020
1.9.0-dev.842 274 6/8/2020
1.9.0-dev.836 269 6/8/2020
1.9.0-dev.786 1,244 5/27/2020
1.9.0-dev.762 577 5/15/2020
1.8.0 18,012 5/15/2020
1.8.0-dev.748 290 5/12/2020
1.8.0-dev.669 538 4/22/2020
1.8.0-dev.668 281 4/21/2020
1.8.0-dev.661 272 4/20/2020
1.8.0-dev.650 274 4/20/2020
1.8.0-dev.639 281 4/20/2020
1.8.0-dev.620 277 4/17/2020
1.7.0 14,029 4/17/2020
1.7.0-dev.608 303 4/16/2020
1.7.0-dev.574 272 4/14/2020
1.7.0-dev.563 279 4/14/2020
1.7.0-dev.534 286 4/6/2020
1.7.0-dev.528 292 4/6/2020
1.7.0-dev.512 323 4/3/2020
1.7.0-dev.495 292 3/30/2020
1.7.0-dev.469 1,135 3/13/2020
1.6.0 2,896 3/13/2020
1.6.0-dev.458 312 3/13/2020
1.6.0-dev.443 313 3/9/2020
1.6.0-dev.422 323 2/28/2020
1.6.0-dev.410 319 2/27/2020
1.6.0-dev.404 319 2/27/2020
1.6.0-dev.356 315 2/14/2020
1.5.0 1,438 2/14/2020
1.5.0-dev.349 300 2/14/2020
1.5.0-dev.341 304 2/12/2020
1.5.0-dev.312 316 1/22/2020
1.4.0 3,915 1/17/2020
1.3.0 2,004 12/6/2019
1.2.0 6,150 11/8/2019
1.1.0 907 10/11/2019
1.0.0 2,390 8/23/2019