InfluxDB.Client 4.15.0-dev.13674

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.15.0-dev.13674                
NuGet\Install-Package InfluxDB.Client -Version 4.15.0-dev.13674                
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.15.0-dev.13674" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add InfluxDB.Client --version 4.15.0-dev.13674                
#r "nuget: InfluxDB.Client, 4.15.0-dev.13674"                
#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.15.0-dev.13674&prerelease

// Install InfluxDB.Client as a Cake Tool
#tool nuget:?package=InfluxDB.Client&version=4.15.0-dev.13674&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 (30)

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.

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.

OpenTelemetry.Exporter.InfluxDB

An OpenTelemetry .NET exporter that exports to 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.19.0-dev.14811 65 9/13/2024
4.18.0 1,976 9/13/2024
4.18.0-dev.14769 97 9/4/2024
4.18.0-dev.14743 57 9/3/2024
4.18.0-dev.14694 54 9/3/2024
4.18.0-dev.14693 39 9/3/2024
4.18.0-dev.14692 40 9/3/2024
4.18.0-dev.14618 53 9/2/2024
4.18.0-dev.14609 44 9/2/2024
4.18.0-dev.14592 37 9/2/2024
4.18.0-dev.14446 198 8/19/2024
4.18.0-dev.14414 101 8/12/2024
4.17.0 28,223 8/12/2024
4.17.0-dev.headers.read.1 155 7/22/2024
4.17.0-dev.14350 37 8/5/2024
4.17.0-dev.14333 36 8/5/2024
4.17.0-dev.14300 36 8/5/2024
4.17.0-dev.14291 34 8/5/2024
4.17.0-dev.14189 62 7/23/2024
4.17.0-dev.14179 48 7/22/2024
4.17.0-dev.14101 149 7/1/2024
4.17.0-dev.14100 54 7/1/2024
4.17.0-dev.14044 89 6/24/2024
4.16.0 23,718 6/24/2024
4.16.0-dev.13990 1,040 6/3/2024
4.16.0-dev.13973 52 6/3/2024
4.16.0-dev.13972 52 6/3/2024
4.16.0-dev.13963 61 6/3/2024
4.16.0-dev.13962 56 6/3/2024
4.16.0-dev.13881 54 6/3/2024
4.16.0-dev.13775 154 5/17/2024
4.16.0-dev.13702 62 5/17/2024
4.15.0 28,235 5/17/2024
4.15.0-dev.13674 75 5/14/2024
4.15.0-dev.13567 726 4/2/2024
4.15.0-dev.13558 58 4/2/2024
4.15.0-dev.13525 56 4/2/2024
4.15.0-dev.13524 58 4/2/2024
4.15.0-dev.13433 207 3/7/2024
4.15.0-dev.13432 62 3/7/2024
4.15.0-dev.13407 92 3/7/2024
4.15.0-dev.13390 60 3/7/2024
4.15.0-dev.13388 56 3/7/2024
4.15.0-dev.13282 243 3/6/2024
4.15.0-dev.13257 70 3/6/2024
4.15.0-dev.13113 1,110 2/1/2024
4.15.0-dev.13104 58 2/1/2024
4.15.0-dev.13081 58 2/1/2024
4.15.0-dev.13040 124 2/1/2024
4.15.0-dev.13039 57 2/1/2024
4.15.0-dev.12863 2,066 1/8/2024
4.15.0-dev.12846 73 1/8/2024
4.15.0-dev.12837 68 1/8/2024
4.15.0-dev.12726 2,564 12/1/2023
4.15.0-dev.12725 80 12/1/2023
4.15.0-dev.12724 67 12/1/2023
4.15.0-dev.12691 77 12/1/2023
4.15.0-dev.12658 77 12/1/2023
4.15.0-dev.12649 70 12/1/2023
4.15.0-dev.12624 74 12/1/2023
4.15.0-dev.12471 982 11/7/2023
4.15.0-dev.12462 74 11/7/2023
4.14.0 377,327 11/7/2023
4.14.0-dev.12437 76 11/7/2023
4.14.0-dev.12343 124 11/2/2023
4.14.0-dev.12310 77 11/2/2023
4.14.0-dev.12284 346 11/1/2023
4.14.0-dev.12235 99 11/1/2023
4.14.0-dev.12226 76 11/1/2023
4.14.0-dev.11972 5,170 8/8/2023
4.14.0-dev.11915 139 7/31/2023
4.14.0-dev.11879 157 7/28/2023
4.13.0 261,702 7/28/2023
4.13.0-dev.11854 96 7/28/2023
4.13.0-dev.11814 350 7/21/2023
4.13.0-dev.11771 143 7/19/2023
4.13.0-dev.11770 102 7/19/2023
4.13.0-dev.11728 124 7/18/2023
4.13.0-dev.11686 197 7/17/2023
4.13.0-dev.11685 87 7/17/2023
4.13.0-dev.11676 102 7/17/2023
4.13.0-dev.11479 1,913 6/27/2023
4.13.0-dev.11478 97 6/27/2023
4.13.0-dev.11477 100 6/27/2023
4.13.0-dev.11396 450 6/19/2023
4.13.0-dev.11395 89 6/19/2023
4.13.0-dev.11342 340 6/15/2023
4.13.0-dev.11330 276 6/12/2023
4.13.0-dev.11305 94 6/12/2023
4.13.0-dev.11296 94 6/12/2023
4.13.0-dev.11217 368 6/6/2023
4.13.0-dev.11089 286 5/30/2023
4.13.0-dev.11064 118 5/30/2023
4.13.0-dev.10998 157 5/29/2023
4.13.0-dev.10989 112 5/29/2023
4.13.0-dev.10871 855 5/8/2023
4.13.0-dev.10870 90 5/8/2023
4.13.0-dev.10819 269 4/28/2023
4.12.0 163,958 4/28/2023
4.12.0-dev.10777 129 4/27/2023
4.12.0-dev.10768 110 4/27/2023
4.12.0-dev.10759 104 4/27/2023
4.12.0-dev.10742 87 4/27/2023
4.12.0-dev.10685 98 4/27/2023
4.12.0-dev.10684 100 4/27/2023
4.12.0-dev.10643 107 4/27/2023
4.12.0-dev.10642 93 4/27/2023
4.12.0-dev.10569 94 4/27/2023
4.12.0-dev.10193 1,736 2/23/2023
4.11.0 107,877 2/23/2023
4.11.0-dev.10176 169 2/23/2023
4.11.0-dev.10059 3,114 1/26/2023
4.10.0 67,544 1/26/2023
4.10.0-dev.10033 140 1/25/2023
4.10.0-dev.10032 117 1/25/2023
4.10.0-dev.10031 124 1/25/2023
4.10.0-dev.9936 3,490 12/26/2022
4.10.0-dev.9935 137 12/26/2022
4.10.0-dev.9881 174 12/21/2022
4.10.0-dev.9880 116 12/21/2022
4.10.0-dev.9818 607 12/16/2022
4.10.0-dev.9773 275 12/12/2022
4.10.0-dev.9756 107 12/12/2022
4.10.0-dev.9693 359 12/6/2022
4.9.0 174,649 12/6/2022
4.9.0-dev.9684 107 12/6/2022
4.9.0-dev.9666 119 12/6/2022
4.9.0-dev.9617 128 12/6/2022
4.9.0-dev.9478 199 12/5/2022
4.9.0-dev.9469 126 12/5/2022
4.9.0-dev.9444 99 12/5/2022
4.9.0-dev.9411 113 12/5/2022
4.9.0-dev.9350 155 12/1/2022
4.8.0 5,373 12/1/2022
4.8.0-dev.9324 199 11/30/2022
4.8.0-dev.9232 179 11/28/2022
4.8.0-dev.9223 117 11/28/2022
4.8.0-dev.9222 113 11/28/2022
4.8.0-dev.9117 395 11/21/2022
4.8.0-dev.9108 119 11/21/2022
4.8.0-dev.9099 119 11/21/2022
4.8.0-dev.9029 191 11/16/2022
4.8.0-dev.8971 121 11/15/2022
4.8.0-dev.8961 125 11/14/2022
4.8.0-dev.8928 125 11/14/2022
4.8.0-dev.8899 129 11/14/2022
4.8.0-dev.8898 139 11/14/2022
4.8.0-dev.8839 122 11/14/2022
4.8.0-dev.8740 240 11/7/2022
4.8.0-dev.8725 117 11/7/2022
4.8.0-dev.8648 359 11/3/2022
4.7.0 99,548 11/3/2022
4.7.0-dev.8625 265 11/2/2022
4.7.0-dev.8594 272 10/31/2022
4.7.0-dev.8579 115 10/31/2022
4.7.0-dev.8557 105 10/31/2022
4.7.0-dev.8540 117 10/31/2022
4.7.0-dev.8518 116 10/31/2022
4.7.0-dev.8517 115 10/31/2022
4.7.0-dev.8509 112 10/31/2022
4.7.0-dev.8377 811 10/26/2022
4.7.0-dev.8360 131 10/25/2022
4.7.0-dev.8350 166 10/24/2022
4.7.0-dev.8335 121 10/24/2022
4.7.0-dev.8334 118 10/24/2022
4.7.0-dev.8223 218 10/19/2022
4.7.0-dev.8178 238 10/17/2022
4.7.0-dev.8170 119 10/17/2022
4.7.0-dev.8148 125 10/17/2022
4.7.0-dev.8133 115 10/17/2022
4.7.0-dev.8097 108 10/17/2022
4.7.0-dev.8034 934 10/11/2022
4.7.0-dev.8025 134 10/11/2022
4.7.0-dev.8009 196 10/10/2022
4.7.0-dev.8001 133 10/10/2022
4.7.0-dev.7959 200 10/4/2022
4.7.0-dev.7905 320 9/30/2022
4.7.0-dev.7875 165 9/29/2022
4.6.0 46,746 9/29/2022
4.6.0-dev.7832 165 9/29/2022
4.6.0-dev.7817 129 9/29/2022
4.6.0-dev.7779 189 9/27/2022
4.6.0-dev.7778 136 9/27/2022
4.6.0-dev.7734 157 9/26/2022
4.6.0-dev.7733 126 9/26/2022
4.6.0-dev.7677 234 9/20/2022
4.6.0-dev.7650 220 9/16/2022
4.6.0-dev.7626 199 9/14/2022
4.6.0-dev.7618 181 9/14/2022
4.6.0-dev.7574 130 9/13/2022
4.6.0-dev.7572 113 9/13/2022
4.6.0-dev.7528 257 9/12/2022
4.6.0-dev.7502 158 9/9/2022
4.6.0-dev.7479 188 9/8/2022
4.6.0-dev.7471 133 9/8/2022
4.6.0-dev.7447 183 9/7/2022
4.6.0-dev.7425 126 9/7/2022
4.6.0-dev.7395 151 9/6/2022
4.6.0-dev.7344 331 8/31/2022
4.6.0-dev.7329 114 8/31/2022
4.6.0-dev.7292 129 8/30/2022
4.6.0-dev.7240 307 8/29/2022
4.5.0 61,028 8/29/2022
4.5.0-dev.7216 143 8/27/2022
4.5.0-dev.7147 301 8/22/2022
4.5.0-dev.7134 333 8/17/2022
4.5.0-dev.7096 177 8/15/2022
4.5.0-dev.7070 268 8/11/2022
4.5.0-dev.7040 187 8/10/2022
4.5.0-dev.7011 237 8/3/2022
4.5.0-dev.6987 137 8/1/2022
4.5.0-dev.6962 155 7/29/2022
4.4.0 49,022 7/29/2022
4.4.0-dev.6901 336 7/25/2022
4.4.0-dev.6843 376 7/19/2022
4.4.0-dev.6804 141 7/19/2022
4.4.0-dev.6789 127 7/19/2022
4.4.0-dev.6760 131 7/19/2022
4.4.0-dev.6705 215 7/14/2022
4.4.0-dev.6663 1,116 6/24/2022
4.4.0-dev.6655 152 6/24/2022
4.3.0 165,065 6/24/2022
4.3.0-dev.multiple.buckets3 289 6/21/2022
4.3.0-dev.multiple.buckets2 257 6/17/2022
4.3.0-dev.multiple.buckets1 132 6/17/2022
4.3.0-dev.6631 143 6/22/2022
4.3.0-dev.6623 128 6/22/2022
4.3.0-dev.6374 454 6/13/2022
4.3.0-dev.6286 986 5/20/2022
4.2.0 69,339 5/20/2022
4.2.0-dev.6257 607 5/13/2022
4.2.0-dev.6248 145 5/12/2022
4.2.0-dev.6233 234 5/12/2022
4.2.0-dev.6194 241 5/10/2022
4.2.0-dev.6193 150 5/10/2022
4.2.0-dev.6158 3,046 5/6/2022
4.2.0-dev.6135 197 5/6/2022
4.2.0-dev.6091 527 4/28/2022
4.2.0-dev.6048 166 4/28/2022
4.2.0-dev.6047 145 4/28/2022
4.2.0-dev.5966 490 4/25/2022
4.2.0-dev.5938 393 4/19/2022
4.1.0 46,515 4/19/2022
4.1.0-dev.5910 358 4/13/2022
4.1.0-dev.5888 154 4/13/2022
4.1.0-dev.5887 160 4/13/2022
4.1.0-dev.5794 850 4/6/2022
4.1.0-dev.5725 551 3/18/2022
4.0.0 58,288 3/18/2022
4.0.0-rc3 957 3/4/2022
4.0.0-rc2 677 2/25/2022
4.0.0-rc1 2,164 2/18/2022
4.0.0-dev.5709 145 3/18/2022
4.0.0-dev.5684 163 3/15/2022
4.0.0-dev.5630 148 3/4/2022
4.0.0-dev.5607 152 3/3/2022
4.0.0-dev.5579 163 2/25/2022
4.0.0-dev.5556 161 2/24/2022
4.0.0-dev.5555 156 2/24/2022
4.0.0-dev.5497 162 2/23/2022
4.0.0-dev.5489 148 2/23/2022
4.0.0-dev.5460 155 2/23/2022
4.0.0-dev.5444 160 2/22/2022
4.0.0-dev.5333 168 2/17/2022
4.0.0-dev.5303 166 2/16/2022
4.0.0-dev.5280 154 2/16/2022
4.0.0-dev.5279 158 2/16/2022
4.0.0-dev.5241 343 2/15/2022
4.0.0-dev.5225 166 2/15/2022
4.0.0-dev.5217 148 2/15/2022
4.0.0-dev.5209 150 2/15/2022
4.0.0-dev.5200 159 2/14/2022
4.0.0-dev.5188 713 2/10/2022
4.0.0-dev.5180 375 2/10/2022
4.0.0-dev.5172 375 2/10/2022
4.0.0-dev.5130 383 2/10/2022
4.0.0-dev.5122 386 2/9/2022
4.0.0-dev.5103 390 2/9/2022
4.0.0-dev.5097 383 2/9/2022
4.0.0-dev.5091 369 2/9/2022
4.0.0-dev.5084 363 2/8/2022
3.4.0-dev.5263 162 2/15/2022
3.4.0-dev.4986 397 2/7/2022
3.4.0-dev.4968 426 2/4/2022
3.3.0 135,468 2/4/2022
3.3.0-dev.4889 419 2/3/2022
3.3.0-dev.4865 416 2/1/2022
3.3.0-dev.4823 329 1/19/2022
3.3.0-dev.4691 1,054 1/7/2022
3.3.0-dev.4557 2,214 11/26/2021
3.2.0 94,781 11/26/2021
3.2.0-dev.4533 5,071 11/24/2021
3.2.0-dev.4484 363 11/11/2021
3.2.0-dev.4475 218 11/10/2021
3.2.0-dev.4387 283 10/26/2021
3.2.0-dev.4363 246 10/22/2021
3.2.0-dev.4356 192 10/22/2021
3.1.0 93,432 10/22/2021
3.1.0-dev.4303 445 10/18/2021
3.1.0-dev.4293 217 10/15/2021
3.1.0-dev.4286 198 10/15/2021
3.1.0-dev.4240 258 10/12/2021
3.1.0-dev.4202 214 10/11/2021
3.1.0-dev.4183 224 10/11/2021
3.1.0-dev.4131 198 10/8/2021
3.1.0-dev.3999 214 10/5/2021
3.1.0-dev.3841 327 9/29/2021
3.1.0-dev.3798 410 9/17/2021
3.0.0 59,590 9/17/2021
3.0.0-dev.3726 2,543 8/31/2021
3.0.0-dev.3719 177 8/31/2021
3.0.0-dev.3671 408 8/20/2021
2.2.0-dev.3652 182 8/20/2021
2.1.0 265,890 8/20/2021
2.1.0-dev.3605 221 8/17/2021
2.1.0-dev.3584 534 8/16/2021
2.1.0-dev.3558 187 8/16/2021
2.1.0-dev.3527 326 7/29/2021
2.1.0-dev.3519 246 7/29/2021
2.1.0-dev.3490 310 7/20/2021
2.1.0-dev.3445 271 7/12/2021
2.1.0-dev.3434 250 7/9/2021
2.0.0 64,554 7/9/2021
2.0.0-dev.3401 7,323 6/25/2021
2.0.0-dev.3368 257 6/23/2021
2.0.0-dev.3361 235 6/23/2021
2.0.0-dev.3330 267 6/17/2021
2.0.0-dev.3291 255 6/16/2021
1.20.0-dev.3218 524 6/4/2021
1.19.0 126,090 6/4/2021
1.19.0-dev.3204 224 6/3/2021
1.19.0-dev.3160 215 6/2/2021
1.19.0-dev.3159 186 6/2/2021
1.19.0-dev.3084 2,502 5/7/2021
1.19.0-dev.3051 266 5/5/2021
1.19.0-dev.3044 220 5/5/2021
1.19.0-dev.3008 249 4/30/2021
1.18.0 35,973 4/30/2021
1.18.0-dev.2973 245 4/27/2021
1.18.0-dev.2930 1,200 4/16/2021
1.18.0-dev.2919 241 4/13/2021
1.18.0-dev.2893 234 4/12/2021
1.18.0-dev.2880 208 4/12/2021
1.18.0-dev.2856 238 4/7/2021
1.18.0-dev.2830 1,839 4/1/2021
1.18.0-dev.2816 200 4/1/2021
1.17.0 45,533 4/1/2021
1.17.0-dev.linq.17 881 3/18/2021
1.17.0-dev.linq.16 251 3/16/2021
1.17.0-dev.linq.15 232 3/15/2021
1.17.0-dev.linq.14 249 3/12/2021
1.17.0-dev.linq.13 284 3/11/2021
1.17.0-dev.linq.12 206 3/10/2021
1.17.0-dev.linq.11 251 3/8/2021
1.17.0-dev.2776 222 3/26/2021
1.17.0-dev.2713 189 3/25/2021
1.17.0-dev.2707 192 3/25/2021
1.17.0-dev.2652 251 3/19/2021
1.17.0-dev.2619 189 3/18/2021
1.17.0-dev.2566 192 3/16/2021
1.17.0-dev.2549 193 3/15/2021
1.17.0-dev.2505 233 3/12/2021
1.17.0-dev.2446 218 3/11/2021
1.17.0-dev.2402 212 3/8/2021
1.17.0-dev.2371 211 3/5/2021
1.16.0 19,187 3/5/2021
1.16.0-dev.linq.10 1,644 2/4/2021
1.16.0-dev.linq.9 230 2/4/2021
1.16.0-dev.2359 244 3/4/2021
1.16.0-dev.2273 204 2/12/2021
1.16.0-dev.2255 210 2/11/2021
1.16.0-dev.2228 212 2/5/2021
1.16.0-dev.2147 251 1/29/2021
1.15.0 32,301 1/29/2021
1.15.0-dev.linq.8 215 1/28/2021
1.15.0-dev.linq.7 205 1/27/2021
1.15.0-dev.linq.6 271 1/20/2021
1.15.0-dev.linq.5 254 1/19/2021
1.15.0-dev.linq.4 383 1/15/2021
1.15.0-dev.linq.3 204 1/14/2021
1.15.0-dev.linq.2 211 1/13/2021
1.15.0-dev.linq.1 233 1/12/2021
1.15.0-dev.2135 201 1/28/2021
1.15.0-dev.2009 209 1/19/2021
1.15.0-dev.1793 224 1/11/2021
1.15.0-dev.1753 260 1/7/2021
1.15.0-dev.1752 248 1/7/2021
1.15.0-dev.1705 867 12/16/2020
1.15.0-dev.1677 572 12/4/2020
1.14.0 45,480 12/4/2020
1.14.0-dev.1665 264 12/3/2020
1.14.0-dev.1648 263 12/2/2020
1.14.0-dev.1632 326 11/27/2020
1.14.0-dev.1577 459 10/30/2020
1.14.0-dev.1571 320 10/30/2020
1.13.0 15,114 10/30/2020
1.13.0-dev.1545 412 10/15/2020
1.13.0-dev.1516 472 10/8/2020
1.13.0-dev.1489 575 10/2/2020
1.13.0-dev.1478 312 10/2/2020
1.12.0 35,914 10/2/2020
1.12.0-dev.1466 258 10/1/2020
1.12.0-dev.1421 559 9/23/2020
1.12.0-dev.1345 325 9/18/2020
1.12.0-dev.1306 328 9/15/2020
1.12.0-dev.1251 339 9/2/2020
1.12.0-dev.1216 1,950 8/14/2020
1.11.0 24,141 8/14/2020
1.11.0-dev.1205 296 8/14/2020
1.11.0-dev.1185 296 8/10/2020
1.11.0-dev.1166 349 7/28/2020
1.11.0-dev.1150 295 7/28/2020
1.11.0-dev.1144 310 7/28/2020
1.11.0-dev.1125 286 7/20/2020
1.11.0-dev.1111 291 7/17/2020
1.10.0 17,045 7/17/2020
1.10.0-dev.1098 273 7/15/2020
1.10.0-dev.1077 391 7/10/2020
1.10.0-dev.1049 405 6/29/2020
1.10.0-dev.1022 322 6/23/2020
1.10.0-dev.1021 307 6/23/2020
1.10.0-dev.990 306 6/19/2020
1.9.0 19,427 6/19/2020
1.9.0-dev.984 324 6/19/2020
1.9.0-dev.971 279 6/17/2020
1.9.0-dev.955 284 6/17/2020
1.9.0-dev.886 299 6/10/2020
1.9.0-dev.848 325 6/8/2020
1.9.0-dev.842 279 6/8/2020
1.9.0-dev.836 279 6/8/2020
1.9.0-dev.786 1,256 5/27/2020
1.9.0-dev.762 588 5/15/2020
1.8.0 18,360 5/15/2020
1.8.0-dev.748 297 5/12/2020
1.8.0-dev.669 549 4/22/2020
1.8.0-dev.668 286 4/21/2020
1.8.0-dev.661 277 4/20/2020
1.8.0-dev.650 279 4/20/2020
1.8.0-dev.639 295 4/20/2020
1.8.0-dev.620 282 4/17/2020
1.7.0 14,335 4/17/2020
1.7.0-dev.608 314 4/16/2020
1.7.0-dev.574 285 4/14/2020
1.7.0-dev.563 284 4/14/2020
1.7.0-dev.534 300 4/6/2020
1.7.0-dev.528 297 4/6/2020
1.7.0-dev.512 330 4/3/2020
1.7.0-dev.495 304 3/30/2020
1.7.0-dev.469 1,145 3/13/2020
1.6.0 2,910 3/13/2020
1.6.0-dev.458 323 3/13/2020
1.6.0-dev.443 318 3/9/2020
1.6.0-dev.422 328 2/28/2020
1.6.0-dev.410 332 2/27/2020
1.6.0-dev.404 324 2/27/2020
1.6.0-dev.356 327 2/14/2020
1.5.0 1,455 2/14/2020
1.5.0-dev.349 305 2/14/2020
1.5.0-dev.341 310 2/12/2020
1.5.0-dev.312 322 1/22/2020
1.4.0 3,928 1/17/2020
1.3.0 2,012 12/6/2019
1.2.0 6,167 11/8/2019
1.1.0 915 10/11/2019
1.0.0 2,834 8/23/2019