InfluxDB.Client 4.8.0-dev.8839

This is a prerelease version of InfluxDB.Client.
There is a newer version of this package available.
See the version list below for details.
dotnet add package InfluxDB.Client --version 4.8.0-dev.8839
NuGet\Install-Package InfluxDB.Client -Version 4.8.0-dev.8839
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.8.0-dev.8839" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add InfluxDB.Client --version 4.8.0-dev.8839
#r "nuget: InfluxDB.Client, 4.8.0-dev.8839"
#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.8.0-dev.8839&prerelease

// Install InfluxDB.Client as a Cake Tool
#tool nuget:?package=InfluxDB.Client&version=4.8.0-dev.8839&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(string[] args)
        {
            var influxDBClient = InfluxDBClientFactory.Create("http://localhost:8086", Token);

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

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

            influxDBClient.Dispose();
        }        
    }
}

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(string[] args)
        {
            var influxDBClient = InfluxDBClientFactory.Create("http://localhost:8086", Token);

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

            //
            // QueryData
            //
            var temperatures = await queryApi.QueryAsync<Temperature>(flux, "org_id");
            temperatures.ForEach(temperature =>
            {
                Console.WriteLine($"{temperature.Location}: {temperature.Value} at {temperature.Time}");
            });

            influxDBClient.Dispose();
        }  
        
        [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(string[] args)
        {
            var influxDBClient = InfluxDBClientFactory.Create("http://localhost:8086", Token);

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

            var queryApi = influxDBClient.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");

            influxDBClient.Dispose();
        }
    }
}

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(string[] args)
        {
            var influxDBClient = InfluxDBClientFactory.Create("http://localhost:8086", Token);

            var flux = "from(bucket:\"temperature-sensors\") |> range(start: 0)";
            
            var queryApi = influxDBClient.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");

            influxDBClient.Dispose();
        }  
        
        [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(string[] args)
        {
            var influxDBClient = InfluxDBClientFactory.Create("http://localhost:8086", Token);

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

            var queryApi = influxDBClient.GetQueryApi();

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

            influxDBClient.Dispose();
        }
    }
}

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(string[] args)
        {
            var influxDBClient = InfluxDBClientFactory.Create("http://localhost:8086", Token);

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

            var queryApi = influxDBClient.GetQueryApi();

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

            influxDBClient.Dispose();
        }
    }
}

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(string[] args)
        {
            using var client = InfluxDBClientFactory.Create("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(string[] args)
        {
            var influxDBClient = InfluxDBClientFactory.Create("http://localhost:8086", Token);

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

                writeApi.WriteMeasurement(temperature, WritePrecision.Ns, "bucket_name", "org_id");
            }
            
            influxDBClient.Dispose();
        }
        
        [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(string[] args)
        {
            var influxDBClient = InfluxDBClientFactory.Create("http://localhost:8086", Token);

            //
            // Write Data
            //
            using (var writeApi = influxDBClient.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");
            }
            
            influxDBClient.Dispose();
        }
    }
}

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(string[] args)
        {
            var influxDBClient = InfluxDBClientFactory.Create("http://localhost:8086", Token);

            //
            // Write Data
            //
            using (var writeApi = influxDBClient.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");
            }
            
            influxDBClient.Dispose();
        }
    }
}
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(string[] args)
        {
            var influxDBClient = InfluxDBClientFactory.Create("http://localhost:8086", Token);

            //
            // Write Data
            //
            using (var writeApi = influxDBClient.GetWriteApi())
            {
                //
                //
                // Write by LineProtocol
                //
                writeApi.WriteRecord("temperature,location=north value=60.0", WritePrecision.Ns,"bucket_name", "org_id");
            }
            
            influxDBClient.Dispose();
        }
    }
}
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(string[] args)
        {
            var influxDbClient = InfluxDBClientFactory.Create("http://localhost:8086", 
                            "my-user", "my-password".ToCharArray());

            //
            // Write Data
            //
            var writeApiAsync = influxDbClient.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()}");
                });
            });
            
            influxDbClient.Dispose();
        }
    }
}
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.Builder()
    .Url(url)
    .AuthenticateToken(token)
    .AddDefaultTag("id", "132-987-655")
    .AddDefaultTag("customer", "California Miner")
    .AddDefaultTag("hostname", "${env.Hostname}")
    .AddDefaultTag("sensor-version", "${SensorVersion}")
    .Build()    

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(string[] args)
        {
            var influxDBClient = InfluxDBClientFactory.Create("http://localhost:8086", Token);

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

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(string[] args)
        {
            const string url = "http://localhost:8086";
            const string token = "my-token";
            const string org = "my-org";
            
            using var client = InfluxDBClientFactory.Create(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.Builder()
                .Url(host)
                .AuthenticateToken(token.ToCharArray())
                .Org(organization)
                .Bucket(bucket)
                .Build();

            var converter = new DomainEntityConverter();
            var client = InfluxDBClientFactory.Create(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.Dispose();
        }
    }
}

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 influxDBClient = 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 influxDBClient = InfluxDBClientFactory
            .Create("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

The WebProxy could be configured via InfluxDBClientOptions.Builder:

var options = new InfluxDBClientOptions.Builder()
    .Url("http://localhost:8086")
    .AuthenticateToken("my-token".ToCharArray())
    .Proxy(new WebProxy("http://proxyserver:80/", true))
    .Build();

var client = InfluxDBClientFactory.Create(options);

Proxy and redirects configuration

You can configure the client to tunnel requests through an HTTP proxy. To configure the proxy use Proxy configuration option:

var options = new InfluxDBClientOptions.Builder()
   .Url("http://localhost:8086")
   .AuthenticateToken("my-token")
   .Proxy(new WebProxy("http://proxyserver:80/", true))
   .Build();

using var client = InfluxDBClientFactory.Create(options);

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

var options = new InfluxDBClientOptions.Builder()
    .Url("http://localhost:8086")
    .AllowRedirects(true)
    .Build();

using var client = InfluxDBClientFactory.Create(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.

influxDBClient.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
AWF.Fabric

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

InfluxDB.Client.Linq

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

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.16.0-dev.13775 97 5/17/2024
4.16.0-dev.13702 49 5/17/2024
4.15.0 2,172 5/17/2024
4.15.0-dev.13674 56 5/14/2024
4.15.0-dev.13567 305 4/2/2024
4.15.0-dev.13558 47 4/2/2024
4.15.0-dev.13525 46 4/2/2024
4.15.0-dev.13524 42 4/2/2024
4.15.0-dev.13433 171 3/7/2024
4.15.0-dev.13432 47 3/7/2024
4.15.0-dev.13407 79 3/7/2024
4.15.0-dev.13390 45 3/7/2024
4.15.0-dev.13388 43 3/7/2024
4.15.0-dev.13282 228 3/6/2024
4.15.0-dev.13257 57 3/6/2024
4.15.0-dev.13113 1,081 2/1/2024
4.15.0-dev.13104 50 2/1/2024
4.15.0-dev.13081 50 2/1/2024
4.15.0-dev.13040 107 2/1/2024
4.15.0-dev.13039 44 2/1/2024
4.15.0-dev.12863 2,035 1/8/2024
4.15.0-dev.12846 59 1/8/2024
4.15.0-dev.12837 55 1/8/2024
4.15.0-dev.12726 2,398 12/1/2023
4.15.0-dev.12725 60 12/1/2023
4.15.0-dev.12724 58 12/1/2023
4.15.0-dev.12691 62 12/1/2023
4.15.0-dev.12658 68 12/1/2023
4.15.0-dev.12649 61 12/1/2023
4.15.0-dev.12624 58 12/1/2023
4.15.0-dev.12471 872 11/7/2023
4.15.0-dev.12462 58 11/7/2023
4.14.0 240,354 11/7/2023
4.14.0-dev.12437 58 11/7/2023
4.14.0-dev.12343 102 11/2/2023
4.14.0-dev.12310 58 11/2/2023
4.14.0-dev.12284 335 11/1/2023
4.14.0-dev.12235 80 11/1/2023
4.14.0-dev.12226 59 11/1/2023
4.14.0-dev.11972 4,591 8/8/2023
4.14.0-dev.11915 119 7/31/2023
4.14.0-dev.11879 142 7/28/2023
4.13.0 217,248 7/28/2023
4.13.0-dev.11854 87 7/28/2023
4.13.0-dev.11814 335 7/21/2023
4.13.0-dev.11771 128 7/19/2023
4.13.0-dev.11770 87 7/19/2023
4.13.0-dev.11728 112 7/18/2023
4.13.0-dev.11686 182 7/17/2023
4.13.0-dev.11685 72 7/17/2023
4.13.0-dev.11676 87 7/17/2023
4.13.0-dev.11479 1,408 6/27/2023
4.13.0-dev.11478 81 6/27/2023
4.13.0-dev.11477 85 6/27/2023
4.13.0-dev.11396 435 6/19/2023
4.13.0-dev.11395 80 6/19/2023
4.13.0-dev.11342 329 6/15/2023
4.13.0-dev.11330 259 6/12/2023
4.13.0-dev.11305 85 6/12/2023
4.13.0-dev.11296 85 6/12/2023
4.13.0-dev.11217 354 6/6/2023
4.13.0-dev.11089 273 5/30/2023
4.13.0-dev.11064 107 5/30/2023
4.13.0-dev.10998 146 5/29/2023
4.13.0-dev.10989 92 5/29/2023
4.13.0-dev.10871 834 5/8/2023
4.13.0-dev.10870 77 5/8/2023
4.13.0-dev.10819 255 4/28/2023
4.12.0 140,861 4/28/2023
4.12.0-dev.10777 115 4/27/2023
4.12.0-dev.10768 101 4/27/2023
4.12.0-dev.10759 90 4/27/2023
4.12.0-dev.10742 78 4/27/2023
4.12.0-dev.10685 90 4/27/2023
4.12.0-dev.10684 86 4/27/2023
4.12.0-dev.10643 94 4/27/2023
4.12.0-dev.10642 85 4/27/2023
4.12.0-dev.10569 80 4/27/2023
4.12.0-dev.10193 1,706 2/23/2023
4.11.0 100,167 2/23/2023
4.11.0-dev.10176 160 2/23/2023
4.11.0-dev.10059 2,605 1/26/2023
4.10.0 64,583 1/26/2023
4.10.0-dev.10033 132 1/25/2023
4.10.0-dev.10032 104 1/25/2023
4.10.0-dev.10031 117 1/25/2023
4.10.0-dev.9936 3,424 12/26/2022
4.10.0-dev.9935 122 12/26/2022
4.10.0-dev.9881 165 12/21/2022
4.10.0-dev.9880 102 12/21/2022
4.10.0-dev.9818 599 12/16/2022
4.10.0-dev.9773 242 12/12/2022
4.10.0-dev.9756 99 12/12/2022
4.10.0-dev.9693 347 12/6/2022
4.9.0 148,631 12/6/2022
4.9.0-dev.9684 99 12/6/2022
4.9.0-dev.9666 106 12/6/2022
4.9.0-dev.9617 117 12/6/2022
4.9.0-dev.9478 185 12/5/2022
4.9.0-dev.9469 118 12/5/2022
4.9.0-dev.9444 91 12/5/2022
4.9.0-dev.9411 105 12/5/2022
4.9.0-dev.9350 141 12/1/2022
4.8.0 4,973 12/1/2022
4.8.0-dev.9324 183 11/30/2022
4.8.0-dev.9232 171 11/28/2022
4.8.0-dev.9223 103 11/28/2022
4.8.0-dev.9222 105 11/28/2022
4.8.0-dev.9117 386 11/21/2022
4.8.0-dev.9108 111 11/21/2022
4.8.0-dev.9099 105 11/21/2022
4.8.0-dev.9029 183 11/16/2022
4.8.0-dev.8971 108 11/15/2022
4.8.0-dev.8961 111 11/14/2022
4.8.0-dev.8928 117 11/14/2022
4.8.0-dev.8899 114 11/14/2022
4.8.0-dev.8898 124 11/14/2022
4.8.0-dev.8839 114 11/14/2022
4.8.0-dev.8740 232 11/7/2022
4.8.0-dev.8725 103 11/7/2022
4.8.0-dev.8648 345 11/3/2022
4.7.0 90,159 11/3/2022
4.7.0-dev.8625 252 11/2/2022
4.7.0-dev.8594 260 10/31/2022
4.7.0-dev.8579 105 10/31/2022
4.7.0-dev.8557 97 10/31/2022
4.7.0-dev.8540 109 10/31/2022
4.7.0-dev.8518 108 10/31/2022
4.7.0-dev.8517 102 10/31/2022
4.7.0-dev.8509 99 10/31/2022
4.7.0-dev.8377 797 10/26/2022
4.7.0-dev.8360 120 10/25/2022
4.7.0-dev.8350 154 10/24/2022
4.7.0-dev.8335 111 10/24/2022
4.7.0-dev.8334 108 10/24/2022
4.7.0-dev.8223 208 10/19/2022
4.7.0-dev.8178 223 10/17/2022
4.7.0-dev.8170 109 10/17/2022
4.7.0-dev.8148 115 10/17/2022
4.7.0-dev.8133 104 10/17/2022
4.7.0-dev.8097 97 10/17/2022
4.7.0-dev.8034 925 10/11/2022
4.7.0-dev.8025 119 10/11/2022
4.7.0-dev.8009 181 10/10/2022
4.7.0-dev.8001 117 10/10/2022
4.7.0-dev.7959 192 10/4/2022
4.7.0-dev.7905 310 9/30/2022
4.7.0-dev.7875 156 9/29/2022
4.6.0 45,415 9/29/2022
4.6.0-dev.7832 150 9/29/2022
4.6.0-dev.7817 115 9/29/2022
4.6.0-dev.7779 179 9/27/2022
4.6.0-dev.7778 128 9/27/2022
4.6.0-dev.7734 144 9/26/2022
4.6.0-dev.7733 118 9/26/2022
4.6.0-dev.7677 219 9/20/2022
4.6.0-dev.7650 212 9/16/2022
4.6.0-dev.7626 189 9/14/2022
4.6.0-dev.7618 165 9/14/2022
4.6.0-dev.7574 114 9/13/2022
4.6.0-dev.7572 104 9/13/2022
4.6.0-dev.7528 249 9/12/2022
4.6.0-dev.7502 150 9/9/2022
4.6.0-dev.7479 175 9/8/2022
4.6.0-dev.7471 125 9/8/2022
4.6.0-dev.7447 172 9/7/2022
4.6.0-dev.7425 112 9/7/2022
4.6.0-dev.7395 138 9/6/2022
4.6.0-dev.7344 317 8/31/2022
4.6.0-dev.7329 104 8/31/2022
4.6.0-dev.7292 113 8/30/2022
4.6.0-dev.7240 299 8/29/2022
4.5.0 54,298 8/29/2022
4.5.0-dev.7216 133 8/27/2022
4.5.0-dev.7147 293 8/22/2022
4.5.0-dev.7134 324 8/17/2022
4.5.0-dev.7096 163 8/15/2022
4.5.0-dev.7070 256 8/11/2022
4.5.0-dev.7040 173 8/10/2022
4.5.0-dev.7011 227 8/3/2022
4.5.0-dev.6987 129 8/1/2022
4.5.0-dev.6962 140 7/29/2022
4.4.0 47,506 7/29/2022
4.4.0-dev.6901 327 7/25/2022
4.4.0-dev.6843 362 7/19/2022
4.4.0-dev.6804 127 7/19/2022
4.4.0-dev.6789 119 7/19/2022
4.4.0-dev.6760 118 7/19/2022
4.4.0-dev.6705 207 7/14/2022
4.4.0-dev.6663 1,104 6/24/2022
4.4.0-dev.6655 138 6/24/2022
4.3.0 140,880 6/24/2022
4.3.0-dev.multiple.buckets3 275 6/21/2022
4.3.0-dev.multiple.buckets2 249 6/17/2022
4.3.0-dev.multiple.buckets1 119 6/17/2022
4.3.0-dev.6631 128 6/22/2022
4.3.0-dev.6623 120 6/22/2022
4.3.0-dev.6374 440 6/13/2022
4.3.0-dev.6286 978 5/20/2022
4.2.0 64,866 5/20/2022
4.2.0-dev.6257 599 5/13/2022
4.2.0-dev.6248 131 5/12/2022
4.2.0-dev.6233 220 5/12/2022
4.2.0-dev.6194 227 5/10/2022
4.2.0-dev.6193 142 5/10/2022
4.2.0-dev.6158 3,038 5/6/2022
4.2.0-dev.6135 183 5/6/2022
4.2.0-dev.6091 513 4/28/2022
4.2.0-dev.6048 157 4/28/2022
4.2.0-dev.6047 131 4/28/2022
4.2.0-dev.5966 482 4/25/2022
4.2.0-dev.5938 377 4/19/2022
4.1.0 44,863 4/19/2022
4.1.0-dev.5910 344 4/13/2022
4.1.0-dev.5888 138 4/13/2022
4.1.0-dev.5887 144 4/13/2022
4.1.0-dev.5794 842 4/6/2022
4.1.0-dev.5725 426 3/18/2022
4.0.0 56,676 3/18/2022
4.0.0-rc3 939 3/4/2022
4.0.0-rc2 665 2/25/2022
4.0.0-rc1 2,151 2/18/2022
4.0.0-dev.5709 137 3/18/2022
4.0.0-dev.5684 149 3/15/2022
4.0.0-dev.5630 130 3/4/2022
4.0.0-dev.5607 142 3/3/2022
4.0.0-dev.5579 155 2/25/2022
4.0.0-dev.5556 148 2/24/2022
4.0.0-dev.5555 142 2/24/2022
4.0.0-dev.5497 149 2/23/2022
4.0.0-dev.5489 141 2/23/2022
4.0.0-dev.5460 142 2/23/2022
4.0.0-dev.5444 145 2/22/2022
4.0.0-dev.5333 161 2/17/2022
4.0.0-dev.5303 152 2/16/2022
4.0.0-dev.5280 147 2/16/2022
4.0.0-dev.5279 145 2/16/2022
4.0.0-dev.5241 330 2/15/2022
4.0.0-dev.5225 153 2/15/2022
4.0.0-dev.5217 141 2/15/2022
4.0.0-dev.5209 137 2/15/2022
4.0.0-dev.5200 151 2/14/2022
4.0.0-dev.5188 698 2/10/2022
4.0.0-dev.5180 367 2/10/2022
4.0.0-dev.5172 362 2/10/2022
4.0.0-dev.5130 370 2/10/2022
4.0.0-dev.5122 379 2/9/2022
4.0.0-dev.5103 377 2/9/2022
4.0.0-dev.5097 376 2/9/2022
4.0.0-dev.5091 360 2/9/2022
4.0.0-dev.5084 355 2/8/2022
3.4.0-dev.5263 149 2/15/2022
3.4.0-dev.4986 389 2/7/2022
3.4.0-dev.4968 418 2/4/2022
3.3.0 121,444 2/4/2022
3.3.0-dev.4889 400 2/3/2022
3.3.0-dev.4865 401 2/1/2022
3.3.0-dev.4823 321 1/19/2022
3.3.0-dev.4691 818 1/7/2022
3.3.0-dev.4557 2,200 11/26/2021
3.2.0 91,120 11/26/2021
3.2.0-dev.4533 5,065 11/24/2021
3.2.0-dev.4484 352 11/11/2021
3.2.0-dev.4475 212 11/10/2021
3.2.0-dev.4387 276 10/26/2021
3.2.0-dev.4363 240 10/22/2021
3.2.0-dev.4356 186 10/22/2021
3.1.0 89,853 10/22/2021
3.1.0-dev.4303 434 10/18/2021
3.1.0-dev.4293 210 10/15/2021
3.1.0-dev.4286 189 10/15/2021
3.1.0-dev.4240 251 10/12/2021
3.1.0-dev.4202 201 10/11/2021
3.1.0-dev.4183 212 10/11/2021
3.1.0-dev.4131 191 10/8/2021
3.1.0-dev.3999 207 10/5/2021
3.1.0-dev.3841 321 9/29/2021
3.1.0-dev.3798 404 9/17/2021
3.0.0 57,735 9/17/2021
3.0.0-dev.3726 2,531 8/31/2021
3.0.0-dev.3719 165 8/31/2021
3.0.0-dev.3671 395 8/20/2021
2.2.0-dev.3652 166 8/20/2021
2.1.0 234,992 8/20/2021
2.1.0-dev.3605 208 8/17/2021
2.1.0-dev.3584 527 8/16/2021
2.1.0-dev.3558 174 8/16/2021
2.1.0-dev.3527 318 7/29/2021
2.1.0-dev.3519 232 7/29/2021
2.1.0-dev.3490 303 7/20/2021
2.1.0-dev.3445 263 7/12/2021
2.1.0-dev.3434 241 7/9/2021
2.0.0 61,998 7/9/2021
2.0.0-dev.3401 6,984 6/25/2021
2.0.0-dev.3368 248 6/23/2021
2.0.0-dev.3361 220 6/23/2021
2.0.0-dev.3330 254 6/17/2021
2.0.0-dev.3291 241 6/16/2021
1.20.0-dev.3218 518 6/4/2021
1.19.0 114,174 6/4/2021
1.19.0-dev.3204 217 6/3/2021
1.19.0-dev.3160 201 6/2/2021
1.19.0-dev.3159 179 6/2/2021
1.19.0-dev.3084 2,494 5/7/2021
1.19.0-dev.3051 252 5/5/2021
1.19.0-dev.3044 206 5/5/2021
1.19.0-dev.3008 241 4/30/2021
1.18.0 35,629 4/30/2021
1.18.0-dev.2973 229 4/27/2021
1.18.0-dev.2930 1,186 4/16/2021
1.18.0-dev.2919 226 4/13/2021
1.18.0-dev.2893 226 4/12/2021
1.18.0-dev.2880 200 4/12/2021
1.18.0-dev.2856 230 4/7/2021
1.18.0-dev.2830 1,825 4/1/2021
1.18.0-dev.2816 188 4/1/2021
1.17.0 44,732 4/1/2021
1.17.0-dev.linq.17 871 3/18/2021
1.17.0-dev.linq.16 238 3/16/2021
1.17.0-dev.linq.15 217 3/15/2021
1.17.0-dev.linq.14 233 3/12/2021
1.17.0-dev.linq.13 271 3/11/2021
1.17.0-dev.linq.12 198 3/10/2021
1.17.0-dev.linq.11 235 3/8/2021
1.17.0-dev.2776 208 3/26/2021
1.17.0-dev.2713 181 3/25/2021
1.17.0-dev.2707 179 3/25/2021
1.17.0-dev.2652 241 3/19/2021
1.17.0-dev.2619 180 3/18/2021
1.17.0-dev.2566 182 3/16/2021
1.17.0-dev.2549 185 3/15/2021
1.17.0-dev.2505 225 3/12/2021
1.17.0-dev.2446 210 3/11/2021
1.17.0-dev.2402 202 3/8/2021
1.17.0-dev.2371 201 3/5/2021
1.16.0 18,964 3/5/2021
1.16.0-dev.linq.10 1,631 2/4/2021
1.16.0-dev.linq.9 223 2/4/2021
1.16.0-dev.2359 230 3/4/2021
1.16.0-dev.2273 197 2/12/2021
1.16.0-dev.2255 196 2/11/2021
1.16.0-dev.2228 203 2/5/2021
1.16.0-dev.2147 244 1/29/2021
1.15.0 31,022 1/29/2021
1.15.0-dev.linq.8 208 1/28/2021
1.15.0-dev.linq.7 198 1/27/2021
1.15.0-dev.linq.6 264 1/20/2021
1.15.0-dev.linq.5 241 1/19/2021
1.15.0-dev.linq.4 376 1/15/2021
1.15.0-dev.linq.3 194 1/14/2021
1.15.0-dev.linq.2 204 1/13/2021
1.15.0-dev.linq.1 220 1/12/2021
1.15.0-dev.2135 194 1/28/2021
1.15.0-dev.2009 202 1/19/2021
1.15.0-dev.1793 209 1/11/2021
1.15.0-dev.1753 253 1/7/2021
1.15.0-dev.1752 241 1/7/2021
1.15.0-dev.1705 860 12/16/2020
1.15.0-dev.1677 563 12/4/2020
1.14.0 44,694 12/4/2020
1.14.0-dev.1665 256 12/3/2020
1.14.0-dev.1648 249 12/2/2020
1.14.0-dev.1632 310 11/27/2020
1.14.0-dev.1577 452 10/30/2020
1.14.0-dev.1571 307 10/30/2020
1.13.0 14,821 10/30/2020
1.13.0-dev.1545 389 10/15/2020
1.13.0-dev.1516 465 10/8/2020
1.13.0-dev.1489 568 10/2/2020
1.13.0-dev.1478 300 10/2/2020
1.12.0 34,209 10/2/2020
1.12.0-dev.1466 243 10/1/2020
1.12.0-dev.1421 545 9/23/2020
1.12.0-dev.1345 315 9/18/2020
1.12.0-dev.1306 311 9/15/2020
1.12.0-dev.1251 332 9/2/2020
1.12.0-dev.1216 1,934 8/14/2020
1.11.0 24,008 8/14/2020
1.11.0-dev.1205 281 8/14/2020
1.11.0-dev.1185 285 8/10/2020
1.11.0-dev.1166 334 7/28/2020
1.11.0-dev.1150 279 7/28/2020
1.11.0-dev.1144 299 7/28/2020
1.11.0-dev.1125 277 7/20/2020
1.11.0-dev.1111 282 7/17/2020
1.10.0 16,970 7/17/2020
1.10.0-dev.1098 263 7/15/2020
1.10.0-dev.1077 381 7/10/2020
1.10.0-dev.1049 393 6/29/2020
1.10.0-dev.1022 307 6/23/2020
1.10.0-dev.1021 297 6/23/2020
1.10.0-dev.990 292 6/19/2020
1.9.0 18,024 6/19/2020
1.9.0-dev.984 313 6/19/2020
1.9.0-dev.971 263 6/17/2020
1.9.0-dev.955 274 6/17/2020
1.9.0-dev.886 289 6/10/2020
1.9.0-dev.848 309 6/8/2020
1.9.0-dev.842 270 6/8/2020
1.9.0-dev.836 265 6/8/2020
1.9.0-dev.786 1,240 5/27/2020
1.9.0-dev.762 575 5/15/2020
1.8.0 17,839 5/15/2020
1.8.0-dev.748 286 5/12/2020
1.8.0-dev.669 536 4/22/2020
1.8.0-dev.668 279 4/21/2020
1.8.0-dev.661 270 4/20/2020
1.8.0-dev.650 272 4/20/2020
1.8.0-dev.639 279 4/20/2020
1.8.0-dev.620 275 4/17/2020
1.7.0 13,907 4/17/2020
1.7.0-dev.608 300 4/16/2020
1.7.0-dev.574 270 4/14/2020
1.7.0-dev.563 277 4/14/2020
1.7.0-dev.534 284 4/6/2020
1.7.0-dev.528 290 4/6/2020
1.7.0-dev.512 321 4/3/2020
1.7.0-dev.495 289 3/30/2020
1.7.0-dev.469 1,133 3/13/2020
1.6.0 2,893 3/13/2020
1.6.0-dev.458 310 3/13/2020
1.6.0-dev.443 311 3/9/2020
1.6.0-dev.422 321 2/28/2020
1.6.0-dev.410 317 2/27/2020
1.6.0-dev.404 317 2/27/2020
1.6.0-dev.356 313 2/14/2020
1.5.0 1,434 2/14/2020
1.5.0-dev.349 297 2/14/2020
1.5.0-dev.341 296 2/12/2020
1.5.0-dev.312 314 1/22/2020
1.4.0 3,906 1/17/2020
1.3.0 2,000 12/6/2019
1.2.0 6,146 11/8/2019
1.1.0 901 10/11/2019
1.0.0 2,089 8/23/2019