<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>InfluxData Blog - Jay Clifford</title>
    <description>Posts by Jay Clifford on the InfluxData Blog</description>
    <link>https://www.influxdata.com/blog/author/jay-clifford/</link>
    <language>en-us</language>
    <lastBuildDate>Wed, 28 Feb 2024 08:00:00 +0000</lastBuildDate>
    <pubDate>Wed, 28 Feb 2024 08:00:00 +0000</pubDate>
    <ttl>1800</ttl>
    <item>
      <title>Building the Next Generation of Smart PLC's With the ctrlX CORE and InfluxDB</title>
      <description>&lt;p&gt;&lt;em&gt;This article was originally published on &lt;a href="https://www.iiot-world.com/industrial-iot/connected-industry/building-the-next-generation-of-smart-plcs-with-the-ctrlx-core-and-influxdb/"&gt;IIoT World&lt;/a&gt; and is reprinted here with permission.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Program Logic Controllers (PLCs) have played an integral role in industrial automation since their initial creation during the 1960s.
&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/2de7018f8c904930b8123dc5f3bf815a/7b22301fc1ff7377727916d72de2bee1/Diagrams__4_.png" alt="" /&gt;
Since then, we’ve seen incremental improvements to their form and function throughout the years. The problem? While PLCs are exceptional at managing and controlling industrial processes, the evolving demands of modern manufacturing require these devices to do more than control machinery. Manufacturers now seek to leverage the computational power of PLCs for more complex tasks, particularly in monitoring the health and status of machines. The need for greater efficiency, &lt;a href="https://www.influxdata.com/resources/enabling-predictive-maintenance-in-industrial-operations-with-influxdb/"&gt;predictive maintenance&lt;/a&gt;, and real-time data analysis drives this shift. So, does this mean we need to revisit how organizations design and use PLCs?&lt;/p&gt;

&lt;p&gt;In this blog, we’ll explore a next-generation PLC called the &lt;a href="https://apps.boschrexroth.com/microsites/ctrlx-automation/en/portfolio/ctrlx-core/"&gt;ctrlX core by Rexroth&lt;/a&gt; and how we can utilize this platform to integrate best-in-class open source projects such as &lt;a href="https://www.influxdata.com/"&gt;InfluxDB&lt;/a&gt; and &lt;a href="https://grafana.com/"&gt;Grafana&lt;/a&gt; to create a modern, interconnected anomaly detection stack.&lt;/p&gt;

&lt;h2 id="what-exactly-is-a-plc"&gt;What exactly is a PLC?&lt;/h2&gt;

&lt;p&gt;Before we get ahead of ourselves, let’s break down a standard PLC’s architecture and role.
&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/132152bc4a7e44448c88d2e36e6ff0c4/1cfd0137b8ad358b84560b3abfccdd5b/Diagrams__6_.png" alt="" /&gt;
The diagram above breaks down a PLC into its core components:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Input Module&lt;/strong&gt;: receives signals from input devices like sensors, switches, and buttons and converts these signals into a format that a PLC CPU can process.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Output Module:&lt;/strong&gt; sends control signals from the PLC to output devices like motors, valves, lights, and relays.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Power Supply:&lt;/strong&gt; converts the main AC (alternating current) to low-voltage DC (direct current) to power the PLC components.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;CPU (Central Processing Unit):&lt;/strong&gt; processes program data and instructions, executing control operations based on programmed logic. It handles logic operations, arithmetic operations, sequencing, timing, counting, and data manipulation.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Memory:&lt;/strong&gt; used to store the control program loaded by the user. This typically includes both volatile and non-volatile memory types. Volatile memory (like RAM) temporarily stores data during operation. Non-volatile memory (like ROM, EEPROM) stores the PLC program and retains it even when power is off.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Programming Device:&lt;/strong&gt; used to input the desired program into the PLC’s memory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I believe breaking down the architecture of a PLC helps to remove the ambiguity behind its design. In its simplest form, it’s a rugged computer that performs and executes a program repeatedly.&lt;/p&gt;

&lt;p&gt;To cement this idea, let’s take a look at a scenario to illustrate a PLC function:
&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/16d873e3944e42cdb664fc5afcf02651/b2f1154b47db477d147c64dba3454828/Diagrams__7_.png" alt="" /&gt;
In the scenario above, the PLC automates the movements of a conveyor:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Start/Stop Control:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Pressing the Start button sends a signal from the PLC to the motor control relay, activating the conveyor belt.&lt;/li&gt;
      &lt;li&gt;Pressing the Stop button or activating the Emergency Stop immediately sends a signal to deactivate the motor control relay, stopping the conveyor.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Object Detection and Handling:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Photoelectric sensors detect objects on the conveyor.&lt;/li&gt;
      &lt;li&gt;The PLC can count objects, control their spacing, and halt the belt for specific operations like inspection or packaging.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Speed Control and Monitoring:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;The speed sensor provides feedback to the PLC.&lt;/li&gt;
      &lt;li&gt;The PLC adjusts the motor speed to maintain a consistent conveyor speed, which can be crucial for synchronized operations with other machinery.&lt;/li&gt;
      &lt;li&gt;The PLC can also respond to manual speed adjustments made by the user.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this basic understanding of how PLCs work, how are next-generation PLCs like the ctrlX core iterating upon this design—and where does InfluxDB come into all of this?&lt;/p&gt;

&lt;h2 id="next-generation-of-plc"&gt;Next generation of PLC&lt;/h2&gt;

&lt;p&gt;As we now know, most standard PLCs have an embedded processor that carries out the devised program. Usually, this means PLCs ship with their own proprietary OS (e.g., Siemens’ SIMATIC Step 7 for their S7 PLCs and Rockwell’s RSLogix for Allen-Bradley PLC) to run on the embedded processor. This is great for providing a fault-tolerant and performant execution engine but leaves very little room for extensibility.&lt;/p&gt;

&lt;p&gt;The ctrlX core, on the other hand, provides a flexible hardware specification, which allows manufacturers to control power levels for their PLC according to the needs of certain tasks. The PLC also deploys a Linux operating system called &lt;a href="https://ubuntu.com/internet-of-things"&gt;Ubuntu IoT Core&lt;/a&gt;, providing the flexibility to extend the core functionality and services users can install on the PLC. Let’s revisit the original PLC architecture and modify it to reflect the design of the ctrlX core:
&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/70d1ce45298b4f8a8fd760db48ff2daa/616f60728e3f7a46ae94ae5840c2a866/Diagrams__8_.png" alt="" /&gt;
We’ve introduced two new aspects to our PLC design:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Data plane:&lt;/strong&gt; this replaces the standard operation data in memory. It still provides a way for our PLC program to access input and output data, as well as a gateway to allow third-party applications to subscribe and publish data.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Third-Party Apps:&lt;/strong&gt; because our PLC now uses a Linux distribution, we can leverage built-in Linux services, such as containerization. This allows developers to build and deploy dockerized applications onto the ctrlX core to interface with the data plane.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Where do InfluxDB and Grafana play into all of this? How can we leverage these new services and the extra compute of the ctrlX core?&lt;/p&gt;

&lt;h2 id="open-source-data-historian"&gt;Open source data historian&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.influxdata.com/"&gt;InfluxDB&lt;/a&gt;, an open source time series database, is specifically engineered from the ground up to handle vast amounts of time series data. In recent years, it has become the foundation for many next-generation data historians that are replacing standard relational databases. We can attribute this shift to several of InfluxDB’s distinctive qualities:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;High-Throughput Data Ingestion:&lt;/strong&gt; InfluxDB efficiently manages data intake from multiple parallel sources, making it ideal for environments with extensive data generation.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Schema-on-Write Flexibility:&lt;/strong&gt; it offers a “schema on write” approach, allowing for the flexible and rapid storage of thousands of machine tags without requiring pre-designed schema. This makes it adaptable to varying data structures.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Low System Requirements:&lt;/strong&gt; with minimal installation and operational demands, InfluxDB is an effective solution for local data storage, conserving hardware resources for other critical PLC processes.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Advanced Time-Based Queries:&lt;/strong&gt; performs efficient time-based aggregations (like average, sum, min, max) across various time granularities (seconds, minutes, hours, days, etc.).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;High-Resolution Timestamps:&lt;/strong&gt; highly granular timestamps (up to nanosecond precision) make it suitable for precise machinery monitoring at a detailed level.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Users can install InfluxDB directly onto the ctrlX core via its third-party app store. This automatically installs the latest open source instance. So, what benefits does this provide to my site engineers? Let’s revisit our conveyor example.&lt;/p&gt;

&lt;h3 id="machine-anomaly-detection"&gt;Machine Anomaly Detection&lt;/h3&gt;

&lt;p&gt;In this example, we deployed the ctrlX core to control our conveyor. Like before, the PLC program includes functions such as:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Stop/Start control&lt;/li&gt;
  &lt;li&gt;Object detection and handling&lt;/li&gt;
  &lt;li&gt;Speed control and monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On top of this, we’ll also deploy InfluxDB to act as a local edge data historian. InfluxDB will connect to the ctrlX core data plane and ingest the following health metrics from the conveyor &lt;a href="https://www.sparkfun.com/servos"&gt;servos&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Vibration&lt;/li&gt;
  &lt;li&gt;Speed&lt;/li&gt;
  &lt;li&gt;Temperature&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the illustration below, we can see that during standard operation, the system stores these sensor metrics in InfluxDB. Grafana connects directly to InfluxDB to display these raw metric readings directly on the HMI to the user:
&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/d1acc0d0348d422ebb8a397a081c2797/f2c1cd507fcc3ae99d9e0b31695431e1/Diagrams__9_.png" alt="" /&gt;
This is standard practice within the industry. However, using the InfluxDB OSS (Open Source Software) built-in task engine, we can perform automated analysis on both historical and current telemetry data to look for trends. Within this InfluxDB task, we compare historic readings to current metrics to learn that there is an upward climb in both temperature and vibration. We use this data to send alerts through Grafana to indicate to the onsite engineer that our current telemetry readings indicate one of the motors is under increasing stress and may require servicing.&lt;/p&gt;

&lt;p&gt;This scenario provides a basic way for InfluxDB and Grafana to introduce predictive maintenance and anomaly detection directly onto the PLC. The benefit of this approach is lower latency when identifying and alerting on potential faults because these processes occur closer to the data source. We also use the hardware capabilities of the PLC rather than introducing another edge device to carry out this analysis.&lt;/p&gt;

&lt;h3 id="edge-data-replication"&gt;Edge Data Replication&lt;/h3&gt;

&lt;p&gt;Lastly, as an added extra, InfluxDB OSS has a built-in feature that can write data from one InfluxDB instance to another remote instance of InfluxDB. This can be either InfluxDB &lt;a href="https://www.influxdata.com/products/influxdb-cloud/serverless/"&gt;Serverless&lt;/a&gt;, &lt;a href="https://www.influxdata.com/products/influxdb-cloud/dedicated/"&gt;Dedicated&lt;/a&gt;, &lt;a href="https://www.influxdata.com/products/influxdb-clustered/"&gt;Clustered (on-prem)&lt;/a&gt;, or even another remote instance of InfluxDB &lt;a href="https://www.influxdata.com/products/influxdb/"&gt;OSS&lt;/a&gt;.
&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/7e7a959ebaff498dbd76422457d56038/46b24442013ecb79d478eb9b5c282f74/Diagrams__10_.png" alt="" /&gt;
This feature allows you to aggregate data from different production lines into a single aggregated repository for further analysis. Some assets include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Anomaly detection between production lines of the same type—discover if one production line begins to deviate from the others.&lt;/li&gt;
  &lt;li&gt;Greater organizational visibility. For instance, if one of your data scientists needs real machine data to train an ML model, this feature provides a non-invasive way to offload the necessary data.&lt;/li&gt;
  &lt;li&gt;Inherent security. InfluxDB acts as the data writer and receiver between OT and IT-based networks—data movement only occurs one way.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The evolution of Industry 4.0 is forcing many manufacturers to think creatively about how they can extract, store, and analyze data from PLCs on the shop floor. For many older systems, this practice won’t change (in these cases, combining &lt;a href="https://www.influxdata.com/blog/ptc-kepware-influxdb-collecting-storing-automation-data/"&gt;PTC Kepware and InfluxDB&lt;/a&gt; will do the trick with most PLCs). However, I hope this blog serves you well when you consider bringing new machinery into your production line. A next-gen PLC like the ctrlX core is built from the ground up to accommodate the flexibility and adaptability of performing both as a robust machine controller and a powerful edge computing device. Pair this with open source projects such as InfluxDB and Grafana, and you’ll be able to develop a cost-effective solution for automating the health analysis of your machines.&lt;/p&gt;

&lt;p&gt;To see how easy it is to configure InfluxDB, I highly recommend checking out this &lt;a href="https://killercoda.com/influxdata/course/Training/iiot-demo"&gt;interactive demo.&lt;/a&gt; I also suggest this walkthrough by Rexroth on &lt;a href="https://developer.community.boschrexroth.com/t5/Store-and-How-to/IIoT-Use-ctrlX-CORE-as-a-monitoring-platform-using-InfluxDB-and/ba-p/65882"&gt;how to install and configure InfluxDB onto the ctrlX core&lt;/a&gt;. If you have any questions about this blog or InfluxDB in general, I highly recommend joining the InfluxDB &lt;a href="https://www.influxdata.com/slack"&gt;community&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Wed, 28 Feb 2024 08:00:00 +0000</pubDate>
      <link>https://www.influxdata.com/blog/building-next-generation-plcs-ctrx-core-influxdb/</link>
      <guid isPermaLink="true">https://www.influxdata.com/blog/building-next-generation-plcs-ctrx-core-influxdb/</guid>
      <category>Developer</category>
      <author>Jay Clifford (InfluxData)</author>
    </item>
    <item>
      <title>InfluxDB 3 Python Client Update: Adding Polars Support</title>
      <description>&lt;p&gt;&lt;img style="padding-bottom: 20px;" src="//images.ctfassets.net/o7xu9whrs0u9/aa9e19dbaaa94389a6f266d328673119/6849a8761512babb73197b93d4611817/DALL_E_2024-01-03_14.45.09_-_Create_a_cartoon-style_scene_reminiscent_of_a_whimsical__fantasy_video_game_world._In_this_play.png" alt="" /&gt;&lt;/p&gt;

&lt;p&gt;It’s been a while since we posted about the &lt;a href="https://github.com/InfluxCommunity/influxdb3-python/tree/main"&gt;InfluxDB 3 Python Client&lt;/a&gt;. Let’s take a look at what’s new!
&lt;br /&gt;&lt;/p&gt;

&lt;h2 id="polars-dataframe-ingest"&gt;Polars Dataframe ingest&lt;/h2&gt;

&lt;p&gt;2023 saw the popularity of a new kid on the block within the data analytics space, &lt;a href="https://pola.rs/"&gt;Polars&lt;/a&gt;. The Polars Data Frame library is an alternative data frame package to the original OG Pandas. Although both cater to the same use cases, each is fundamentally built on different technologies.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/b1e1626a05d842dd8ae5906372f6f69a/d26f1f761d2321697965aab062cb7b2d/Time_Series_Analytics_with_Apache_Arrow__Pandas_and_Parquet.png" alt="" /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;One of the most frequent community requests we received was to provide greater compatibility with Polars. Since Polars is built on Apache Arrow, we extended the mode function to include  &lt;strong&gt;&lt;code&gt;polars&lt;/code&gt;&lt;/strong&gt;. Simply query the data and modify the mode to &lt;strong&gt;&lt;code&gt;polars&lt;/code&gt;&lt;/strong&gt; as below:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-python"&gt;import polars as pl
from influxdb_client_3 import InfluxDBClient3

with InfluxDBClient3(
    token="",
    host="eu-central-1-1.aws.cloud2.influxdata.com",
    org="6a841c0c08328fb1") as client:

        sql = 'SELECT * FROM caught LIMIT 100000'
        df = client.query(database="pokemon-codex", query=sql, language='sql', mode='polars')
        print(df, flush=True)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We call the Polars function &lt;strong&gt;&lt;code&gt;from_arrow()&lt;/code&gt;&lt;/strong&gt; within the underlying client code. This automatically converts our Arrow table into a Polars Dataframe. Note: you must install the Polars Dataframe library to use this mode.&lt;/p&gt;

&lt;p&gt;&lt;img style="padding: 20px 0px;" src="//images.ctfassets.net/o7xu9whrs0u9/c1995d1799fe4b139b98ba08746be2be/be7a0e02e5da650b4bf00a203d594abc/Screenshot_2024-01-05_at_15.23.58.png" alt="" /&gt;&lt;/p&gt;

&lt;p&gt;Ingestion was a slightly different story. Like V1 and V2, InfluxDB 3 expects line protocol (LP) as its primary ingestion method. This means we build out converters to LP in our client libraries. Polars provides an extremely efficient &lt;a href="https://docs.pola.rs/user-guide/expressions/user-defined-functions/"&gt;UDF feature&lt;/a&gt;, which made creating this new converter straightforward to implement. We built the new Polars data frame converter into the preexisting data frame converter class. Here is an example:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-python"&gt;import polars as pl
from influxdb_client_3 import InfluxDBClient3,InfluxDBError,WriteOptions,write_client_options

class BatchingCallback(object):

    def success(self, conf, data: str):
        print(f"Written batch: {conf}, data: {data}")

    def error(self, conf, data: str, exception: InfluxDBError):
        print(f"Cannot write batch: {conf}, data: {data} due: {exception}")

    def retry(self, conf, data: str, exception: InfluxDBError):
        print(f"Retryable error occurs for batch: {conf}, data: {data} retry: {exception}")

callback = BatchingCallback()

write_options = WriteOptions(batch_size=10000,
                                        flush_interval=10_000,
                                        jitter_interval=2_000,
                                        retry_interval=5_000,
                                        max_retries=10,
                                        max_retry_delay=15_000,
                                        exponential_base=2, max_close_wait=900_000)

wco = write_client_options(success_callback=callback.success,
                          error_callback=callback.error,
                          retry_callback=callback.retry,
                          WriteOptions=write_options 
                        )

client = InfluxDBClient3(
    token="token",
    host="eu-central-1-1.aws.cloud2.influxdata.com",
    org="6a841c0c08328fb1", enable_gzip=True, write_client_options=wco)

pl_df =pl.read_parquet('pokemon_100_000.parquet')

client.write(database="pokemon-codex", 
             record=pl_df, data_frame_measurement_name='caught', 
             data_frame_tag_columns=['trainer', 'id', 'num'], 
             data_frame_timestamp_column='timestamp')

client.close()&lt;/code&gt;&lt;/pre&gt;

&lt;div class="pt-4"&gt;&lt;/div&gt;

&lt;p&gt;In this case, you can see it includes the same parameters we would use when writing a Pandas data frame. We distinguish the data frame type and call the right converter within the write API.&lt;/p&gt;

&lt;p&gt;&lt;img style="padding: 20px 0px;" src="//images.ctfassets.net/o7xu9whrs0u9/7a3e1e50a5c6437f86a98a45d0902053/83aff89b847f39b2c03cadaced08b1ca/Screenshot_2024-01-05_at_14.59.44.png" alt="" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Top Tip:&lt;/strong&gt; Make sure to include the &lt;strong&gt;&lt;code&gt;data_frame_timestamp_column=&lt;/code&gt;&lt;/strong&gt; and specify your timestamp column. Polars does not provide an index method like Pandas, so we cannot automatically distinguish which is the correct column.&lt;/p&gt;

&lt;h2 id="custom-arrow-flight-headers"&gt;Custom Arrow Flight headers&lt;/h2&gt;

&lt;p&gt;Another requested feature was the inclusion of custom &lt;a href="https://arrow.apache.org/docs/python/generated/pyarrow.flight.FlightCallOptions.html#pyarrow.flight.FlightCallOptions"&gt;Arrow Flight Call Options&lt;/a&gt; for queries. This allows users familiar with Arrow Flight to use the underlying configuration parameters. A simple example could be increasing the timeout for a particular query:
&lt;br /&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-python"&gt;df = client.query(database="pokemon-codex", query=sql, language='sql', mode='polars', timeout=5)&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="bugs-and-miscellaneous"&gt;Bugs and miscellaneous&lt;/h2&gt;

&lt;p&gt;Lastly, here is a minor change history list:&lt;/p&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Version&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;Change&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;0.3.4 / 0.3.3&lt;/td&gt;
      &lt;td&gt;Merged V2 Write API into V3 and removed the V2 client library as a dependency.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;0.3.4 / 0.3.3&lt;/td&gt;
      &lt;td&gt;Added custom port declaration for clustered users&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;0.3.2&lt;/td&gt;
      &lt;td&gt;Fixed Pandas as an optional dependency issue&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;0.3.1&lt;/td&gt;
      &lt;td&gt;Added flight errors readme&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;0.3.1&lt;/td&gt;
      &lt;td&gt;Added community and cookbook example&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;0.3.0&lt;/td&gt;
      &lt;td&gt;Added custom certificates parameter. (To fix Windows-based gRPC SSL issue)&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id="whats-next"&gt;What’s next?&lt;/h2&gt;

&lt;p&gt;We hope you find the new features added to the InfluxDB 3.0 Python Client library useful. If you have any feature requests or bugs to report, please do not hesitate to open an issue via the &lt;a href="https://github.com/InfluxCommunity/influxdb3-python/tree/main"&gt;client repo&lt;/a&gt;. We are always looking for community contributors for our 3.0 client libraries. You can always discuss your contribution with us on &lt;a href="https://influxcommunity.slack.com/archives/C02UDUPLQKA"&gt;Slack&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Fri, 26 Jan 2024 08:00:00 +0000</pubDate>
      <link>https://www.influxdata.com/blog/influxdb-3-python-client-update-polars/</link>
      <guid isPermaLink="true">https://www.influxdata.com/blog/influxdb-3-python-client-update-polars/</guid>
      <category>Developer</category>
      <author>Jay Clifford (InfluxData)</author>
    </item>
    <item>
      <title>Grafana Unleashes Official InfluxDB V3 Data Source: A Quick-start Guide to Configuration and Usage</title>
      <description>&lt;p&gt;Yes, the title says it all: Grafana released the official V3 plugin for &lt;a href="https://www.influxdata.com/products/influxdb-overview/"&gt;InfluxDB&lt;/a&gt; Data Source!&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/e35d55017f5e43a998aa48baa316d4bc/488d199d19df383a34d1cea1131ac82d/Diagrams__11_.png" alt="" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Before delving into the tutorial, we’d like to thank Ismail Simsek, a Tech Lead at &lt;a href="https://www.influxdata.com/grafana/"&gt;Grafana&lt;/a&gt;. Ismail was pivotal in adding the V3 SQL plugin to the InfluxDB data source and making significant backend code improvements.&lt;/em&gt;&lt;/strong&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;To clarify, this release isn’t an entirely new data source. Rather, it integrates the community-developed &lt;a href="https://www.influxdata.com/glossary/apache-arrow-flight-sql/"&gt;Flight SQL&lt;/a&gt; plugin into the official InfluxDB data source, incorporating several highly requested features and performance improvements. This blog teaches you how to configure the new data source plugin with your InfluxDB V3 instance.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/df5df1f3cdc14c74825e3eba04ac5d6f/ba485efd5577b04f185fc3a5b86f32e5/Screenshot_2024-01-17_at_13.17.34.png" alt="" /&gt;&lt;/p&gt;

&lt;h2 id="where-can-i-find-the-v3-data-source"&gt;Where can I find the V3 data source?&lt;/h2&gt;

&lt;p&gt;The V3 Flight SQL plugin has been added to the official InfluxDB data source within Grafana. Below is a table of the Grafana edition and the version you need to install to use it:&lt;/p&gt;

&lt;div class="table-container is-v-centered text-18 py-3"&gt;
&lt;table class="table is-bordered"&gt;
&lt;thead&gt;
&lt;tr style="background-color: #F1F4F6;"&gt;
&lt;td style="width: 50%;"&gt;&lt;b&gt;Edition&lt;/b&gt;&lt;/td&gt;
&lt;td style="width: 50%;"&gt;&lt;b&gt;Version&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Grafana OSS&lt;/td&gt;
&lt;td&gt;10.3.0+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Grafana Enterpise&lt;/td&gt;
&lt;td&gt;10.3.0+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Grafana Cloud&lt;/td&gt;
&lt;td&gt;Latest&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;Let’s jump into Grafana Cloud and locate the official InfluxDB V3 Datasource:&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/c30d0e11808a4f2c9d2db4373b918366/a9c07be103e70c942d098f4912a8c3fb/Screenshot_2024-01-18_at_11.25.27.png" alt="" /&gt;&lt;/p&gt;

&lt;p&gt;Here is our Grafana Cloud instance. On the left-hand navigation panel, we select &lt;strong&gt;Data Source&lt;/strong&gt;. From there, we select &lt;strong&gt;Add data source&lt;/strong&gt; and choose the official InfluxDB data source from the time series database list.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/9486955a81174ecf89fb7df182c1092c/715de27933a28520f53388cb0fdbb8c5/Screenshot_2024-01-18_at_11.28.39.png" alt="" /&gt;&lt;/p&gt;

&lt;p&gt;So no big changes there! We find and create our new InfluxDB data source in the same way we always have. Let’s move on to configuration and learn how to tap into the V3 SQL plugin.&lt;/p&gt;

&lt;h2 id="how-do-i-configure-my-v3-data-source"&gt;How do I configure my V3 data source?&lt;/h2&gt;

&lt;p&gt;As usual, we need to give the data source a useful name. In this case, I aptly named the data source &lt;strong&gt;InfluxDB V3&lt;/strong&gt;. Next, we need to select our &lt;strong&gt;Query language&lt;/strong&gt;—this is also where we enable our V3 plugin.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/cf1720aaadc8453894d5ac03f42c0215/5caf34a5e97cf07d22e15612a9011a25/Screenshot_2024-01-18_at_11.34.56.png" alt="" /&gt;&lt;/p&gt;

&lt;p&gt;Within the drop-down list, you will now see a third option, &lt;strong&gt;SQL.&lt;/strong&gt; Selecting SQL as a new language automatically utilizes the newly integrated Flight SQL API within the Grafana backend. This also transforms the rest of the form parameters we need to fill out.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/3cda8aa6d1af48f8a8a5169115dc4297/4a44b4787ae70e78289802bd26125a56/Screenshot_2024-01-18_at_11.51.34.png" alt="" /&gt;&lt;/p&gt;

&lt;p&gt;You will need to define the following:&lt;/p&gt;

&lt;div class="table-container is-v-centered text-18"&gt;
&lt;table class="table is-bordered"&gt;
&lt;thead&gt;
&lt;tr style="background-color: #F1F4F6;"&gt;
&lt;td style="width: 17%;"&gt;Parameter&lt;/td&gt;
&lt;td&gt;Description&lt;/td&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;URL&lt;/td&gt;
&lt;td&gt;The InfluxDB V3 host you wish to connect to. In this case, if you omit the port it will automatically default to the protocol's default port (http -&amp;gt; 80, https -&amp;gt;443). Here are some accepted examples:
&lt;ul&gt;
 	&lt;li&gt;Serverless: &lt;a href="https://eu-central-1-1.aws.cloud2.influxdata.com"&gt;https://eu-central-1-1.aws.cloud2.influxdata.com&lt;/a&gt;&lt;/li&gt;
 	&lt;li&gt;Serverless: &lt;a href="https://eu-central-1-1.aws.cloud2.influxdata.com:443"&gt;https://eu-central-1-1.aws.cloud2.influxdata.com:443&lt;/a&gt;&lt;/li&gt;
 	&lt;li&gt;Dedicated: &lt;a href="https://b0c7cce5-8dbc-428e-98c6-7f996fb96424.a.influxdb.io"&gt;https://b0c7cce5-8dbc-428e-98c6-7f996fb96424.b.influxdb.io&lt;/a&gt;&lt;/li&gt;
 	&lt;li&gt;Dedicated: &lt;a href="https://b0c7cce5-8dbc-428e-98c6-7f996fb96424.a.influxdb.io"&gt;https://b0c7cce5-8dbc-428e-98c6-7f996fb96424.b.influxdb.io:443&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;b&gt;Note: Port definition is currently only important for clustered and eventually OSS / Community users.&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;Define the database/bucket name you wish to query from. Note that this is a one-to-one ratio as part of the Grafana data source implementation. In this case, we are connecting to a database called &lt;b&gt;factory&lt;/b&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Token&lt;/td&gt;
&lt;td&gt;Lastly, you need to create a token with at least read-only privilege for the specific database you defined.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;After completing the form, select &lt;strong&gt;Save &amp;amp; test.&lt;/strong&gt; This should result in a successful connection to the InfluxDB V3 data source.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/751b8584d9394649bd3edc7f02b5226e/bd7d272ce5932c854712060f51c6e4b5/Screenshot_2024-01-18_at_12.59.31.png" alt="" /&gt;&lt;/p&gt;

&lt;h2 id="a-quick-101"&gt;A quick 101&lt;/h2&gt;

&lt;p&gt;Now that we connected Grafana to InfluxDB V3, let’s build a simple visualization and discuss some features along the way. For this demo, I used data generated from the &lt;a href="https://github.com/InfluxCommunity/Arrow-Task-Engine"&gt;Arrow Task Engine demo&lt;/a&gt;.
&lt;br /&gt;&lt;/p&gt;

&lt;h3 id="data-explorer"&gt;Data Explorer&lt;/h3&gt;

&lt;p&gt;Within the Explore panel, we select our InfluxDB V3 data source. This provides an SQL explorer for navigating our current database schema as well as building basic SQL queries.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/cdb02be5bc9e4425a2e1fb7616d553af/49727ab8478e1f9092dd80e15c262cb8/Screenshot_2024-01-18_at_13.15.45.png" alt="" /&gt;&lt;/p&gt;

&lt;p&gt;Let’s start by creating a table that shows all columns from the last hour.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/86d2ec8b01fc40df8407e20fd4fedfdd/1fedb85d08c85554dda619c21839da1d/Screenshot_2024-01-18_at_13.20.29.png" alt="" /&gt;&lt;/p&gt;

&lt;p&gt;To generate this table, we simply select—via the drop-down panels—the table (measurement) and columns (tags and fields) we would like to view. We can also formulate more specific SQL queries as well:&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/e1aaebde1ad742ff8ff57e357223e83b/eecad3e70046f39dbad160df0e33c019/Screenshot_2024-01-18_at_13.27.37.png" alt="" /&gt;&lt;/p&gt;

&lt;p&gt;After generating some SQL using the basic explorer, can I edit the SQL? The quick answer is yes; simply toggle from &lt;strong&gt;Builder&lt;/strong&gt; to &lt;strong&gt;Code.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/827406922f7b4c92b7f9fe23fe51560f/c9bb3dd704eef1b5324a0f3d77a91765/Screenshot_2024-01-18_at_13.31.48.png" alt="" /&gt;&lt;/p&gt;

&lt;h3 id="from-table-to-time-series"&gt;From Table to Time Series&lt;/h3&gt;

&lt;p&gt;Because InfluxDB 3.0 now returns tables rather than table streams, the V3 plugin defaults to the Grafana table format. Let’s build a query and transform it into the time series format for visualization as a line graph.&lt;/p&gt;

&lt;p&gt;Here is our SQL:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-sql"&gt;SELECT "vibration", "machineID", time 
FROM iox.machine_data 
WHERE time &amp;gt;= $__timeFrom AND time &amp;lt;= $__timeTo AND "machineID" = 'machine1' 
ORDER BY time
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that we must add &lt;code&gt;ORDER BY time&lt;/code&gt; to our query to ensure the order of our timestamps.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/a565938b91f24a8283837d5195cb02c1/cb7278b3f6f96a26af22be2ec96f83b4/Screenshot_2024-01-18_at_13.36.57.png" alt="" /&gt;&lt;/p&gt;

&lt;p&gt;Now we can simply change the &lt;strong&gt;Format&lt;/strong&gt; using the dropdown menu from &lt;em&gt;table&lt;/em&gt; to &lt;em&gt;Time series&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/37141c53cdfe4a0982bb3c6677eeee02/87386bc8a1a1da44c2569545cde6b080/Screenshot_2024-01-18_at_13.38.54.png" alt="" /&gt;&lt;/p&gt;

&lt;p&gt;We will save this query to a dashboard to explore our final feature in this blog: query-based dashboard variables.&lt;/p&gt;

&lt;h3 id="dashboard-variables"&gt;Dashboard Variables&lt;/h3&gt;

&lt;p&gt;One feature missing from the Flight SQL community plugin was query-based dashboard variables. These allow you to define a query to populate a Grafana dashboard dropdown. You can then use these variables within your other queries to create a more dynamic experience.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/289804c3ace04ddeb03f863f5b77a034/4833feb59e95b3787a7e1f84ca188ba7/Screenshot_2024-01-18_at_14.04.40.png" alt="" /&gt;&lt;/p&gt;

&lt;p&gt;In this example, we created a dashboard variable to list individual machine tags. This can be utilized within our line graph query by referencing &lt;code&gt;$machineID&lt;/code&gt; (the name of the dashboard variable).&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-sql"&gt;SELECT "vibration", "machineID", time 
FROM iox.machine_data 
WHERE time &amp;gt;= $__timeFrom AND time &amp;lt;= $__timeTo AND "machineID" = '$machineID' 
ORDER BY time
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/420f1916f53d43a29673e2fead4422f9/3e4e987b4b936e8e04d2ac0f7731b656/Screenshot_2024-01-18_at_14.12.25.png" alt="" /&gt;&lt;/p&gt;

&lt;p&gt;At the top left of the image, you can see our populated dashboard variable. We selected &lt;strong&gt;machine2&lt;/strong&gt;, which appears to show an anomaly…&lt;/p&gt;

&lt;h2 id="next-steps"&gt;Next steps&lt;/h2&gt;

&lt;p&gt;We are extremely excited to see the new and improved &lt;a href="https://www.influxdata.com/products/influxdb-overview/"&gt;InfluxDB&lt;/a&gt; data source in the hands of the community. We hope the new plugin provides a streamlined experience to start interacting with InfluxDB V3 via its Flight SQL interface. As you may have noticed, this new plugin is still alpha, so if you have any issues/feature requests, please let us know via our &lt;a href="https://www.influxdata.com/slack"&gt;Slack community&lt;/a&gt; or open an issue within the &lt;a href="https://github.com/grafana/grafana/issues"&gt;Grafana repo&lt;/a&gt;. We have only scratched the surface of the changes made within the InfluxDB data source rewrite. Make sure to check out the next blog, in which we will dive deeper into some of the features and implementation, including moving the data source to the Grafana backend.&lt;/p&gt;

&lt;p&gt;You can see all this in action here:&lt;/p&gt;
&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/jGclGsv5PBA?si=cNtMMPKD5RZ-wdHl" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""&gt;&lt;/iframe&gt;
</description>
      <pubDate>Mon, 22 Jan 2024 08:00:00 +0000</pubDate>
      <link>https://www.influxdata.com/blog/official-influxdb-v3-data-source-grafana-released/</link>
      <guid isPermaLink="true">https://www.influxdata.com/blog/official-influxdb-v3-data-source-grafana-released/</guid>
      <category>Developer</category>
      <author>Jay Clifford (InfluxData)</author>
    </item>
    <item>
      <title>Quix Community Plugins for InfluxDB: Build Your Own Streaming Task Engine</title>
      <description>&lt;p&gt;With our plans for &lt;a href="https://www.influxdata.com/blog/the-plan-for-influxdb-3-0-open-source/"&gt;InfluxDB 3.0 OSS&lt;/a&gt; laid out, both myself and the rest of the DevRel team have been actively searching for ecosystem platforms that would be logical integrations for the future of &lt;a href="https://www.influxdata.com/products/influxdb-overview/"&gt;InfluxDB&lt;/a&gt;. One of these platforms is Quix!&lt;/p&gt;

&lt;p&gt;Quix is a comprehensive solution tailored for crafting, launching, and overseeing event streaming applications using Python. If you’re looking to sift through time series or event data in real-time for instant decision-making, Quix is your go-to. What we discovered is that it makes a great alternative task engine for InfluxDB 3.0. If you would like to see our initial project with Quix to create an anomaly detection pipeline, check out this &lt;a href="https://www.influxdata.com/blog/predictive-analytics-using-time-series-database/"&gt;blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Progressing from this, we are extremely pleased to announce the release of two InfluxDB Community plugins for Quix. In this blog post, we will break down what each plugin does and provide an example of a use case you can try out yourself.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/2w4cPlvL50znvXWHyTx4fQ/6e8f9242da99009aa5ee6e781cc4bfac/Quix-Community-Plugins-for-InfluxDB-OG.png" alt="Quix-Community-Plugins-for-InfluxDB-OG" /&gt;&lt;/p&gt;

&lt;h2 id="the-plugins"&gt;The plugins&lt;/h2&gt;
&lt;p&gt;The community contributions comprise two plugins:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;InfluxDB Source: This plugin allows users to query InfluxDB 3.0 using &lt;a href="https://www.influxdata.com/glossary/apache-arrow-flight-sql/"&gt;Apache Arrow Flight&lt;/a&gt; on a user-defined interval, parse the data into a pandas DataFrame, and publish to a Quix stream topic.&lt;/li&gt;
  &lt;li&gt;InfluxDB Destination: This plugin allows users to ingest a DataFrame from a Quix stream topic, and define its structure (measurement and tags) before writing the data to an InfluxDB instance (this is compatible with both InfluxDB 2.x and 3.x).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/3xU4ZH9khsHJP0kxEzEoSW/a27c2132d4487cf1d78fdebf55d7fd35/quix-influxdb-image18.png" alt="quix-influxdb-image18" /&gt;&lt;/p&gt;

&lt;p&gt;You can find these plugins in the Quix platform by navigating to “Code Samples” via the menu on the left and searching for “InfluxDB”. Let’s take a look at the configuration of each of these plugins individually.&lt;/p&gt;

&lt;h3 id="influxdb-source"&gt;InfluxDB Source&lt;/h3&gt;
&lt;p&gt;InfluxDB Source is a Python-based plugin, so within the Quix environment it’s highly customizable based on your needs. You may simply edit the Python script within their cloud-based editor before deployment. Let’s start with an overview of the “out of the box” plugin.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/7tWVpBTaMP1L0Lhs6YAY65/8eaab4fe499456831861762532cca120/quix-influxdb-image19.png" alt="quix-influxdb-image19" /&gt;&lt;/p&gt;

&lt;p&gt;The InfluxDB Source plugin requires the following environment variables to be defined in order to run:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;output&lt;/strong&gt;: This is the output topic that will receive the stream (Default: influxdb, Required: True)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;task_interval&lt;/strong&gt;: Interval to run query. Must be within the InfluxDB notation; 1s, 1m, 1h, 1d, 1w, 1mo, 1y (Default: 5m, Required: True)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;INFLUXDB_HOST&lt;/strong&gt;: Host address for the InfluxDB instance. (Default: eu-central-1-1.aws.cloud2.influxdata.com, Required: True)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;INFLUXDB_TOKEN&lt;/strong&gt;: Authentication token to access InfluxDB. (Default: &lt;code&gt;&amp;lt;TOKEN&amp;gt;&lt;/code&gt;, Required: True)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;INFLUXDB_ORG&lt;/strong&gt;: Organization name in InfluxDB. (Default: &lt;code&gt;&amp;lt;ORG&amp;gt;&lt;/code&gt;, Required: False)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;INFLUXDB_DATABASE&lt;/strong&gt;: Database name in InfluxDB where data is stored. (Default: &lt;code&gt;&amp;lt;DATABASE&amp;gt;&lt;/code&gt;, Required: True)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;INFLUXDB_MEASUREMENT_NAME&lt;/strong&gt;: The InfluxDB measurement to read data from. If not specified, the name of the output topic will be used (Default: &lt;code&gt;&amp;lt;INSERT MEASUREMENT&amp;gt;&lt;/code&gt;, Required: True)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once these parameters are set the script will run as follows:&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/1N0zQOBUh548xfAhVx15vN/8524aa4802d2f1f52744bb66f0823bd5/quix-influxdb-image1.png" alt="quix-influxdb-image1" /&gt;&lt;/p&gt;

&lt;p&gt;As seen in the diagram, this plugin loops until shutdown. Based on the provided interval the script sleeps before repeating the query. The interval is also used to formulate the query since we will query only the latest data based on how long the plugin has slept for. Note that the plugin pushes the resulting data using the &lt;a href="https://quix.io/docs/client-library/subscribe.html?h=dataframe#pandas-dataframe-format"&gt;DataFrame&lt;/a&gt; format.&lt;/p&gt;

&lt;h3 id="influxdb-destination"&gt;InfluxDB Destination&lt;/h3&gt;
&lt;p&gt;The InfluxDB Destination plugin – like the Source plugin, is purely Python-based – enables you to customize how the plugin writes data to InfluxDB (a feature we will use in the demo). For now, let’s start with another overview of the “out of the box” plugin.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/6Pjmf404EBbSUYzJMeZtjx/b4adf187160d748048655958ad4d19d2/quix-influxdb-image5.png" alt="quix-influxdb-image5" /&gt;&lt;/p&gt;

&lt;p&gt;The InfluxDB Destination plugin requires you to define the following environment variables in order to run:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;input&lt;/strong&gt;: This is the input topic (Default: detection-result, Required: True)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;INFLUXDB_HOST&lt;/strong&gt;: Host address for the InfluxDB instance. (Default: eu-central-1-1.aws.cloud2.influxdata.com, Required: True)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;INFLUXDB_TOKEN&lt;/strong&gt;: Authentication token to access InfluxDB. (Default: &lt;code&gt;&amp;lt;TOKEN&amp;gt;&lt;/code&gt;, Required: True)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;INFLUXDB_ORG&lt;/strong&gt;: Organization name in InfluxDB. (Default: &lt;code&gt;&amp;lt;ORG&amp;gt;&lt;/code&gt;, Required: False)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;INFLUXDB_DATABASE&lt;/strong&gt;: Database name in InfluxDB where data should be stored. (Default: &lt;code&gt;&amp;lt;DATABASE&amp;gt;&lt;/code&gt;, Required: True)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;INFLUXDB_TAG_COLUMNS&lt;/strong&gt;: Columns to be used as tags when writing data to InfluxDB. (Default: &lt;code&gt;['tag1', 'tag2']&lt;/code&gt;, Required: False)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;INFLUXDB_MEASUREMENT_NAME&lt;/strong&gt;: The InfluxDB measurement to write data to. If not specified, the name of the input topic will be used. (Default: &lt;code&gt;&amp;lt;INSERT MEASUREMENT&amp;gt;&lt;/code&gt;, Required: False)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once these parameters are set the script will run as follows:&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/1PXz8OCdvAdSXAO54SRzOT/d22816a7bc0e926f54652f80976d65ba/quix-influxdb-image7.png" alt="quix-influxdb-image7" /&gt;&lt;/p&gt;

&lt;p&gt;As the diagram shows, on startup the script loads the given environment variables and initializes the InfluxDB Client. It then waits for the chosen topic to stream data to the plugin. The streamed data is received as a pandas DataFrame so we need to apply some basic transformations (rename time column, set time as index) before writing to InfluxDB. From there, we write the DataFrame to InfluxDB based upon the schema specified within the environment variables.&lt;/p&gt;

&lt;h2 id="the-demo"&gt;The demo&lt;/h2&gt;
&lt;p&gt;Now that we have discussed each plugin and its respective design, let’s apply them to an industrial IoT use case.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/2w4cPlvL50znvXWHyTx4fQ/6e8f9242da99009aa5ee6e781cc4bfac/Quix-Community-Plugins-for-InfluxDB-OG.png" alt="Quix-Community-Plugins-for-InfluxDB-OG" /&gt;&lt;/p&gt;

&lt;p&gt;In this example, we have three machines on a production line producing sensor data and writing to an MQTT broker (for this use case we are using HiveMQ). The payload for each machine is within a JSON structure which looks like this.&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-json"&gt;{"metadata": {"machineID": "machine1", "barcode": "31856669", "provider": "Miller-Phillips"}, "data": [{"temperature": 40}, {"load": 100}, {"power": 204}, {"vibration": 90}]}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We will start by connecting the Quix MQTT client to the HiveMQ broker.&lt;/p&gt;

&lt;h3 id="mqtt-client---quix---influxdb"&gt;MQTT Client -&amp;gt; Quix -&amp;gt; InfluxDB&lt;/h3&gt;
&lt;p&gt;First, I located the MQTT plugin, which connects to the broker and writes the data to a Quix Stream (the one on the right).&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/7r5UMgbIxRfLRdYmquAZMI/939973a673cc2aec263a0594910fd4a1/quix-influxdb-image15.png" alt="quix-influxdb-image15" /&gt;&lt;/p&gt;

&lt;p&gt;On inspection of the code, I realized I needed to make a minor code change because I was connecting to a broker that didn’t require TLS authentication. I needed to remove these lines:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-python"&gt;# we'll be using tls
mqtt_client.tls_set(tls_version = mqtt.client.ssl.PROTOCOL_TLS)
mqtt_client.username_pw_set(os.environ["mqtt_username"], os.environ["mqtt_password"])&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, I used the provided environment variables to establish my connection to the broker.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/19X2cye00rpIdcJQnpbdRN/3da440a99b2298f68352157783dd67b4/quix-influxdb-image6.png" alt="quix-influxdb-image6" /&gt;&lt;/p&gt;

&lt;p&gt;Then click &lt;strong&gt;new deployment&lt;/strong&gt;. Configure our resource limits (default is fine) and click &lt;strong&gt;deploy&lt;/strong&gt;. With that our first stage is complete.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/6rMXV6zMFFEqXDHVjZ2IUX/026e8e6be4223d13d2a3ca1eec219b8e/quix-influxdb-image9.png" alt="quix-influxdb-image9" /&gt;&lt;/p&gt;

&lt;p&gt;Next, we need to write this data to InfluxDB. For this, we make use of the new destination plugin with some alterations.&lt;/p&gt;

&lt;p&gt;We follow a similar process to select the InfluxDB 3.0 destination plugin and generate a project. Now we have a slight issue to overcome. Currently, the destination plugin only supports ingesting Quix DataFrames. In our case, we are writing Event Data in JSON. So we need to write a small transformation function for event-based data, which you can see here:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-python"&gt;def on_event_data_received_handler(stream_consumer: qx.StreamConsumer,data: qx.EventData):
    with data:
        jsondata = json.loads(data.value)
        metadata = jsondata['metadata']
        data_points = jsondata['data']
        fields = {k: v for d in data_points for k, v in d.items()}
        timestamp = str(data.timestamp)

        point = {"measurement": measurement_name, "tags" : metadata, "fields": fields, "time": timestamp}

        print(point)
        client.write(record=point)

def on_stream_received_handler(stream_consumer: qx.StreamConsumer):

    # subscribe to new DataFrames being received
    # if you aren't familiar with DataFrames there are other callbacks available
    # refer to the docs here: https://docs.quix.io/sdk/subscribe.html
    stream_consumer.timeseries.on_dataframe_received = on_dataframe_received_handler

    stream_consumer.events.on_data_received = on_event_data_received_handler&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The majority of the code you will use is already there. The main element we added was the &lt;strong&gt;on_event_data_received_handler&lt;/strong&gt;. Now that we have done this, we define our environment variables like we did for the MQTT connector.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/4PUleGa35LN8JzBaYnLusE/c701370f1369502fa78018f7a3dc1ab8/quix-influxdb-image16.png" alt="quix-influxdb-image16" /&gt;&lt;/p&gt;

&lt;p&gt;A note on two of these environment variables:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;You can modify &lt;code&gt;InfluxDB_token&lt;/code&gt; to a secure environment variable to secure your token.&lt;/li&gt;
  &lt;li&gt;We are not using &lt;code&gt;InfluxDB_tag&lt;/code&gt; in this example because we are using the metadata within our JSON payload as our tags.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Click on &lt;strong&gt;new deployment&lt;/strong&gt;. Configure our resource limits (default is fine) and click &lt;strong&gt;deploy&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/7DtpSBnfbF41pCIE1z9ZVk/e3d0c9b9ef7807c214fefaf1bb3a2162/quix-influxdb-image17.png" alt="quix-influxdb-image17" /&gt;&lt;/p&gt;

&lt;p&gt;We are now writing raw machine data to our chosen measurement within InfluxDB. Let’s move on to how we can utilize Quix as a task-based engine to transform our stored raw data.&lt;/p&gt;

&lt;h3 id="influxdb---quix-transform---influxdb"&gt;InfluxDB -&amp;gt; Quix (Transform) -&amp;gt; InfluxDB&lt;/h3&gt;
&lt;p&gt;We will utilize the out-of-the-box configurations for both community plugins to piece together a transformation task. The transformation task is simple:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Query the last 1-minute worth of data&lt;/li&gt;
  &lt;li&gt;Add a new column that checks if the vibration over that interval surpassed a user-defined threshold. This column will contain true or false based on the outcome.&lt;/li&gt;
  &lt;li&gt;Write the data back to a new table within InfluxDB&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s start with querying the data from InfluxDB. This time we are going to utilize our InfluxDB 3.0 Source plugin. Like our previous examples, we search for and select this from the &lt;strong&gt;Code Samples&lt;/strong&gt; library and create a project.&lt;/p&gt;

&lt;p&gt;We do not need to modify any of the plugin code for this one. Just simply define our environment variables:&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/2hSs29LFm5YLydO5HiaWyz/cf98b27dc72f37e7373c7532fbe44963/quix-influxdb-image14.png" alt="quix-influxdb-image14" /&gt;&lt;/p&gt;

&lt;p&gt;We then click &lt;strong&gt;new deployment&lt;/strong&gt;. Configure our resource limits (default is fine) and click &lt;strong&gt;deploy&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/5b8YvFyKh6Yrswu6ohkKL8/9f587b9d9e6608dd9a19debc565c3f0f/quix-influxdb-image13.png" alt="quix-influxdb-image13" /&gt;&lt;/p&gt;

&lt;p&gt;Our query data is now being written directly as a DataFrame for the topic InfluxDB. We can now deploy and create a series of transformation plugins to reshape our data. For this example, we are going to keep it simple:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Ingest the DataFrame&lt;/li&gt;
  &lt;li&gt;Use basic conditional logic within the vibration column to check if it surpasses our predefined threshold&lt;/li&gt;
  &lt;li&gt;Create the new boolean column and write the DataFrame to a new topic reader for ingestion.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The code looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-python"&gt;import quixstreams as qx
import os
import pandas as pd

client = qx.QuixStreamingClient()

topic_consumer = client.get_topic_consumer(os.environ["input"], consumer_group = "empty-transformation")
topic_producer = client.get_topic_producer(os.environ["output"])

def on_dataframe_received_handler(stream_consumer: qx.StreamConsumer, df: pd.DataFrame):

        vibration_limit = int(os.environ["vibration_limit"])
        df['over_limit'] = df['vibration'] &amp;gt; vibration_limit

        stream_producer = topic_producer.get_or_create_stream(stream_id = stream_consumer.stream_id)
        stream_producer.timeseries.buffer.publish(df)

def on_event_data_received_handler(stream_consumer: qx.StreamConsumer, data: qx.EventData):
    print(data)
    # handle your event data here

def on_stream_received_handler(stream_consumer: qx.StreamConsumer):
    stream_consumer.events.on_data_received = on_event_data_received_handler # register the event data callback
    stream_consumer.timeseries.on_dataframe_received = on_dataframe_received_handler

topic_consumer.on_stream_received = on_stream_received_handler

print("Listening to streams. Press CTRL-C to exit.")

qx.App.run()&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Based on this basic transformation plugin we have three environment variables to define.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/208utXlIbXIjdaqSvo64T6/e7e02ea0c24976a5a478d39cc60073ac/quix-influxdb-image11.png" alt="quix-influxdb-image11" /&gt;&lt;/p&gt;

&lt;p&gt;We then click &lt;strong&gt;new deployment&lt;/strong&gt;. Configure our resource limits (default is fine) and click &lt;strong&gt;deploy&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/3HQnFsVDZppnwCL4eHyhE4/5239ccd00f832eb6baae941e19d4e97d/quix-influxdb-image3.png" alt="quix-influxdb-image3" /&gt;&lt;/p&gt;

&lt;p&gt;Our final step is writing the data back to InfluxDB. For this task, we deploy another instance of our InfluxDB Destination plugin. This time, because we ingest the DataFrame from our transformation topic, we only need to define the environment variables.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/6zOFFkbxl8zbPLVLj5DtGk/ecde934b28b1d8a8e91ccd06bf16f037/quix-influxdb-image12.png" alt="quix-influxdb-image12" /&gt;&lt;/p&gt;

&lt;p&gt;Notes on two of these environment variables:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code&gt;InfluxDB_measurement&lt;/code&gt; writes our transformed data to a new table called &lt;code&gt;transformed&lt;/code&gt;. InfluxDB creates this table on demand.&lt;/li&gt;
  &lt;li&gt;We are providing a string array for the columns we wish to define as tags:&lt;code&gt;['machineID', 'barcode', 'provider']&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We then click &lt;strong&gt;new deployment&lt;/strong&gt;. Configure our resource limits (default is fine) and click &lt;strong&gt;deploy&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/6S91mYnTDS4JCUh23SBsXk/93578a53a66aa3ed7fdac9b8455413f1/quix-influxdb-image8.png" alt="quix-influxdb-image8" /&gt;&lt;/p&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;There you have it! We successfully deployed our event streaming pipeline and task engine for InfluxDB. From a birds-eye view it looks like this.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/6gWePbdU4h6345MaTkDZua/0ebe324dbcdb77c95becae253dc7e333/quix-influxdb-image10.png" alt="quix-influxdb-image10" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Thanks Quix for the great user interface)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here is what our raw machine data and transformed data look like in InfluxDB.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/2fIMhJILgScByAOOpkvID7/54c52024b35b383781f1ac8206c227e9/quix-influxdb-image20.png" alt="quix-influxdb-image20" /&gt;
&lt;em&gt;(Raw Machine Data)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/52yIfX7DSuVxpMNZEzktl7/ea070fdf491935b760739d151264feed/quix-influxdb-image4.png" alt="quix-influxdb-image4" /&gt;
&lt;em&gt;(Transformed Machine Data)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In summary, we utilized the Quix platform along with the new InfluxDB Community plugins to ingest ‘live’ raw machine data from three MQTT topics, store this data within InfluxDB, and then derive new value from our stored data. &lt;strong&gt;So where could you go next?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;My hope is you can take this example, adapt it to your own needs, and scale it using the Quix platform. The major benefit of using Quix is we can efficiently scale the number of Sources, Transformations, and Destinations to fit our needs. A great example of this would be to expand our task engine:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Downsampling script&lt;/li&gt;
  &lt;li&gt;Anomaly detection algorithm&lt;/li&gt;
  &lt;li&gt;Check and Alert script&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each script would subscribe to our InfluxDB topic and work in parallel with one another, making efficient use of the data within the event streaming pipeline compared to conventional task methods which would re-query the data.&lt;/p&gt;

&lt;p&gt;You can find the source code for a similar project &lt;a href="https://github.com/InfluxCommunity/quix-anomaly-detection-example"&gt;here&lt;/a&gt;. If you have any questions or would like to discuss InfluxDB or Quix further, come hang out with us within our &lt;a href="https://www.influxdata.com/slack"&gt;Slack channel&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Wed, 18 Oct 2023 08:00:00 +0000</pubDate>
      <link>https://www.influxdata.com/blog/quix-community-plugins-influxdb-build-streaming-task-engine/</link>
      <guid isPermaLink="true">https://www.influxdata.com/blog/quix-community-plugins-influxdb-build-streaming-task-engine/</guid>
      <category>Product</category>
      <author>Jay Clifford (InfluxData)</author>
    </item>
    <item>
      <title>Infrastructure Monitoring Basics with Telegraf, InfluxDB, and Grafana</title>
      <description>&lt;p&gt;Earlier this year, I had the pleasure of speaking at the &lt;a href="https://www.youtube.com/watch?v=ESub4SAKouI&amp;amp;list=PLbzoR-pLrL6osxY8Ao02UdjFIYux9I-Qi&amp;amp;index=164"&gt;Open Source Summit North America&lt;/a&gt;. When choosing a topic, I felt it was time to return to our roots and discuss the subject that originally put InfluxDB on the map: infrastructure monitoring.&lt;/p&gt;

&lt;p&gt;What was especially exciting was the opportunity to showcase the new &lt;a href="https://www.influxdata.com/resources/influxdb-3-0-vs-oss/"&gt;capabilities of InfluxDB 3.0&lt;/a&gt; to the open source community and explain their significance for the future of infrastructure monitoring use cases.&lt;/p&gt;

&lt;p&gt;This blog breaks down the key points from that presentation and delves deeper into those topics, offering further insights and discussion.&lt;/p&gt;

&lt;h2 id="monitoring-vs-observability"&gt;Monitoring vs observability&lt;/h2&gt;

&lt;p&gt;InfluxDB has the ability to tackle both monitoring and observability use cases. 3.0 not only improves the performance of both but also makes Observability use cases viable at scale. Before we jump into the details, let’s level set and discuss what exactly the difference is between &lt;a href="https://www.influxdata.com/blog/observability-vs-monitoring-understanding-differences"&gt;monitoring and observability&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monitoring:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Monitoring involves the collection and analysis of metrics, logs, and events to keep track of system performance. Using predefined rules and thresholds, the monitoring process detects potential issues and generates alerts when threshold breaches occur, thereby helping to maintain system health. You can apply this approach across various types of infrastructure, in both the physical and the digital realms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observability:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Observability takes monitoring a step further to include the instrumentation of both code and infrastructure to expose pertinent data. This empowers teams to deeply understand the behavior of their systems. By correlating data from diverse sources, it facilitates the diagnosis of issues and the identification of root causes. This, in turn, provides actionable insights for effective problem-solving. Tracing, which maps the journey of requests or transactions through components of a system, is the quintessential observability tool.&lt;/p&gt;

&lt;p&gt;At a glance, monitoring and observability might appear to serve the same purpose, but they approach system health from distinct angles. Monitoring is proactive, setting predefined rules and thresholds to ensure systems are operating within desired parameters. It’s about ensuring everything is “on track” and alerting when it’s not. On the other hand, observability is more diagnostic in nature. It’s about understanding “why” something happened and drilling down into system behavior. While both aim to maintain system health and performance, monitoring is more about detecting known issues, whereas observability focuses on exploring unknown issues. However, in the landscape of modern system management, they are complementary. Together, they provide a holistic view of system health, performance, and behavior, ensuring both robustness and resilience.&lt;/p&gt;

&lt;h3 id="monitoring-and-observability-fields"&gt;Monitoring and observability fields&lt;/h3&gt;

&lt;p&gt;We can further categorize these concepts into several distinct fields, each with its specific focus and application:&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/4QEd9ZHkB2aqtIbYXnOflx/75d392818a03ee74cee920cce0746426/categorize-these-concepts-into-fields.png" alt="categorize-these-concepts-into-fields" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.influxdata.com/resources/network-monitoring-with-influxdata/"&gt;Network monitoring&lt;/a&gt;&lt;/strong&gt;: Observing the performance of network components such as routers, switches, and firewalls to ensure efficient data transmission, detect bottlenecks, and identify security threats.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Server monitoring:&lt;/strong&gt; Tracking the performance and availability of physical or virtual servers, including CPU usage, memory consumption, disk space, and response times, to ensure optimal performance and reduce downtime.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.influxdata.com/resources/application-performance-monitoring-apm-using-the-influxdb-time-series-platform"&gt;Application performance monitoring&lt;/a&gt; (APM)&lt;/strong&gt;: Monitoring the performance of software applications to identify issues, bottlenecks, and inefficiencies in the code, databases, or infrastructure components. (Application performance monitoring has been highlighted in blue as it can also fall into the realm of observability which we will cover later on).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cloud infrastructure monitoring:&lt;/strong&gt; Tracking the performance and availability of cloud-based services, such as virtual machines, storage, and databases, to optimize resource allocation and minimize costs.&lt;/p&gt;

&lt;h2 id="a-problem-to-solve"&gt;A problem to solve&lt;/h2&gt;

&lt;p&gt;Now, onto the fun part! I always find that when you have a problem to solve, it is easier to do so if you first learn about the solution you wish to employ. Let’s ask ChatGPT to create an infrastructure problem which involves creating a solution to monitoring each field we discussed earlier.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/3kg4v6UFxurSKciPWhxPij/7c054b28ff0fa91a9480146de1fcad07/image14.jpg" alt="Whisper GPT" /&gt;&lt;/p&gt;

&lt;p&gt;So based on this problem, we can break the architecture down into our monitoring and observability subfields:&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/4JumnI0sXmFq2MLeuxAF7B/f337a0460af8565b111a058174be6293/monitoring-and-observability-subfields.png" alt="monitoring-and-observability-subfields" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Network monitoring&lt;/strong&gt;: Monitor network traffic, especially requests to models.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Server monitoring&lt;/strong&gt;: Track the performance of Whisper GPT servers hosting their primary models, focusing on CPU and GPU metrics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Application performance monitoring (APM)&lt;/strong&gt;: This encompasses two aspects:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Monitoring our Kubernetes cluster on barebone infrastructure.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Providing developers with tools to proactively analyze code within the Whisper platform.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Cloud infrastructure monitoring&lt;/strong&gt;: Utilize services like App Runner or Amazon EKS for front-end management.&lt;/p&gt;

&lt;h2 id="solving-the-problem"&gt;Solving the problem&lt;/h2&gt;

&lt;p&gt;Now, I am going to show you how we can tackle each of these problems using the TIG stack (&lt;a href="https://www.influxdata.com/time-series-platform/telegraf/"&gt;Telegraf&lt;/a&gt;, &lt;a href="https://www.influxdata.com/products/influxdb-overview/"&gt;InfluxDB 3.0&lt;/a&gt; and &lt;a href="https://www.influxdata.com/partners/grafana/"&gt;Grafana&lt;/a&gt;) and &lt;a href="https://www.influxdata.com/blog/opentelemetry-tutorial-collect-traces-logs-metrics-influxdb-3-0-jaeger-grafana/"&gt;OpenTelemetry&lt;/a&gt;. Before we get ahead of ourselves let’s start by creating an architectural blueprint.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/4YQyuQY42kQZnIyZmfYCUg/07b13ee9cf14061a782af5ec916f075b/architectural-blueprint.png" alt="architectural-blueprint" /&gt;&lt;/p&gt;

&lt;h3 id="data-collection"&gt;Data collection&lt;/h3&gt;

&lt;p&gt;Telegraf is our go-to open source data collection agent designed specifically for gathering metrics and events. Equipped with more than &lt;a href="https://www.influxdata.com/products/integrations/"&gt;300 plugins&lt;/a&gt; for both ingesting, transforming, and outputting data, it is a versatile agent for time series data. The community refers to it as the Swiss army knife of monitoring and observability data collection due to its ability to deploy both pull and push collection methods based on the plugin’s use. It is also equipped to handle the parsing of a considerable number of data formats, including Prometheus, JSON, XML, CSV, and &lt;a href="https://github.com/influxdata/telegraf/tree/master/plugins/parsers"&gt;many more&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s take a look at some of the plugins we might use to solve our Whisper GPT problem:&lt;/p&gt;

&lt;div class="table-container is-v-centered"&gt;
&lt;table class="table is-bordered"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;td style="width: 50%;"&gt;&lt;b&gt;Field&lt;/b&gt;&lt;/td&gt;
&lt;td style="width: 50%;"&gt;&lt;b&gt;Plugins&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Network monitoring&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/influxdata/telegraf/blob/master/plugins/inputs/gnmi/README.md"&gt;gNMI&lt;/a&gt;&lt;br /&gt;

&lt;a href="https://github.com/influxdata/telegraf/tree/master/plugins/inputs/net"&gt;Net&lt;/a&gt;&lt;br /&gt;

&lt;a href="https://github.com/influxdata/telegraf/blob/master/plugins/inputs/snmp/README.md"&gt;SNMP&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server monitoring&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/influxdata/telegraf/blob/master/plugins/inputs/cpu/README.md"&gt;CPU&lt;/a&gt;&lt;br /&gt;

&lt;a href="https://github.com/influxdata/telegraf/blob/master/plugins/inputs/disk/README.md"&gt;Disk&lt;/a&gt;&lt;br /&gt;

&lt;a href="https://github.com/influxdata/telegraf/blob/master/plugins/inputs/diskio/README.md"&gt;Diskio&lt;/a&gt;&lt;br /&gt;

&lt;a href="https://github.com/influxdata/telegraf/blob/master/plugins/inputs/mem/README.md"&gt;Mem&lt;/a&gt;&lt;br /&gt;

&lt;a href="https://github.com/influxdata/telegraf/tree/master/plugins/inputs/processes"&gt;Processes&lt;/a&gt;&lt;br /&gt;

&lt;a href="https://github.com/influxdata/telegraf/tree/master/plugins/inputs/nvidia_smi"&gt;Nvidia SMI&lt;/a&gt;&lt;br /&gt;

&lt;a href="https://github.com/influxdata/telegraf/tree/master/plugins/inputs/system"&gt;System&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;APM&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/influxdata/telegraf/tree/master/plugins/inputs/kube_inventory" target="_blank"&gt;Kubernetes Inventory&lt;/a&gt;&lt;br /&gt;

&lt;a href="https://github.com/influxdata/telegraf/tree/master/plugins/inputs/kubernetes" target="_blank"&gt;Kubernetes&lt;/a&gt;&lt;br /&gt;

&lt;a href="https://github.com/influxdata/telegraf/tree/master/plugins/inputs/opentelemetry" target="_blank"&gt;OpenTelemetry&lt;/a&gt;&lt;br /&gt;

&lt;a href="https://github.com/influxdata/telegraf/tree/master/plugins/inputs/prometheus" target="_blank"&gt;Prometheus&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud infrastructure monitoring&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/influxdata/telegraf/tree/master/plugins/inputs/cloudwatch" target="_blank"&gt;CloudWatch&lt;/a&gt;&lt;br /&gt;

&lt;a href="https://github.com/influxdata/telegraf/tree/master/plugins/inputs/kube_inventory" target="_blank"&gt;Kubernetes Inventory&lt;/a&gt;&lt;br /&gt;

&lt;a href="https://github.com/influxdata/telegraf/tree/master/plugins/inputs/kubernetes" target="_blank"&gt;Kubernetes&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;By design, Telegraf acts like a data pipeline that you can route through different plugins to process and aggregate the data before reaching its final output. The following architecture diagram visualizes this nicely.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/6lZBm1kOuPmvS6QyKNjFHM/c8edd22496c3d0c55ad3e6f920900a32/architecture-diagram.png" alt="architecture-diagram" /&gt;&lt;/p&gt;

&lt;p&gt;At this point of the presentation, I delved into Telegraf best practices and initial deployment. I highly recommend checking out our &lt;a href="https://university.influxdata.com/courses/telegraf-basics-tutorial/"&gt;InfluxDB University course on Telegraf&lt;/a&gt; to learn more about this part.&lt;/p&gt;

&lt;h3 id="data-storage"&gt;Data storage&lt;/h3&gt;

&lt;p&gt;Having checked data collection off our list, now let’s move on to establishing the keystone within our infrastructure monitoring architecture… data storage.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/46fUKDlk4MFduG8pT9H7Mg/80a6a1986fb5c04ade3c4abd4dc87193/data-storage.png" alt="data-storage" /&gt;&lt;/p&gt;

&lt;p&gt;InfluxDB 3.0 is a purpose-built time series database built for handling metrics, traces, and logs at a massive scale for real-time analytics. This is driven by the three core open source technologies we use to create our database engine: &lt;a href="https://www.influxdata.com/glossary/apache-arrow/"&gt;Apache Arrow&lt;/a&gt;, &lt;a href="https://www.influxdata.com/glossary/apache-parquet/"&gt;Parquet&lt;/a&gt; and &lt;a href="https://www.influxdata.com/glossary/apache-datafusion/"&gt;DataFusion&lt;/a&gt;. If you would like to learn more about how we deploy these technologies, I highly recommend checking out this &lt;a href="https://www.influxdata.com/blog/influxdb-3-0-system-architecture/"&gt;blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/1610PTEw5IsZROpiYzVybz/4a3e8c6335d1ddcff359e4d92b96e7b8/core-open-source-technologies.png" alt="core-open-source-technologies" /&gt;&lt;/p&gt;

&lt;p&gt;At its very core, InfluxDB offers us some considerable benefits when it comes to our use case:&lt;/p&gt;

&lt;div class="table-container is-v-centered"&gt;
&lt;table class="table is-bordered"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;td style="width: 35%;"&gt;Benefit&lt;/td&gt;
&lt;td style="width: 65%;"&gt;Description&lt;/td&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Schema on write&lt;/td&gt;
&lt;td&gt;This is a no-brainer when it comes to monitoring use cases. Schema design is one of the most costly and time-consuming tasks developers need to focus on when using a conventional database. It is also an issue that will not go away because, depending on how Whisper GPT evolves, the schema will as well. InfluxDB constructs the schema on initial data ingest, removing the need to build out a schema from scratch. This capability allows the schema to evolve along with our solution.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Write and query performance&lt;/td&gt;
&lt;td&gt;In most monitoring use cases, users require near-real-time visibility on the data they are ingesting and this can come from hundreds of data sources generating gigabytes of time series data a day. InfluxDB can ingest over 4 million values per second while providing millisecond query return times. I highly recommend checking out this &lt;a href="https://www.influxdata.com/blog/influxdb-3-0-is-2.5x-45x-faster-compared-to-influxdb-open-source/"&gt;blog to see some of our performance stats&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Single data store&lt;/td&gt;
&lt;td&gt;One of the most interesting issues to solve within the monitoring and observability space is the storage of different types of time series data: traces, metrics and logs. Most seasoned providers use different data storage technologies for each and then provide an interface for joining these results at query time. InfluxDB 3.0 allows us to keep everything in a single store, reducing the overall cost of ownership.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Query support&lt;/td&gt;
&lt;td&gt;With InfluxDB 3.0, we wanted to emphasize meeting developers where they are. This meant providing query languages that most users, whether current and new, can engage with. InfluxQL and SQL give developers performant options for interfacing with their data. They also provide a rich ecosystem to third-party solutions that make use of both languages.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;At this point, I, again, discussed best practices and getting started with InfluxDB 3.0. I highly recommend checking out the &lt;a href="https://university.influxdata.com/courses/influxdbu-essentials-iox/"&gt;InfluxDB 3.0 Essentials course&lt;/a&gt; to catch up on this content.&lt;/p&gt;

&lt;h3 id="data-in-action"&gt;Data in action&lt;/h3&gt;

&lt;p&gt;We have reached our second milestone. At this point, our Whisper GPT infrastructure monitoring process is collecting and storing data.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/5TL7PlhAgxU0bPLnUZ6ZtV/f3accf4c4ff8ff31e42c534fe9a178a6/data-in-action.png" alt="data-in-action" /&gt;&lt;/p&gt;

&lt;p&gt;Now we need to do something with this data. Depending on your own initiatives or current company infrastructure, you might have a pretty good idea how this part is going to shape out. For the sake of completeness, let’s discuss some ideas.&lt;/p&gt;

&lt;p&gt;Grafana is an open source data visualization and monitoring platform. It allows users to create interactive dashboards for real-time data analysis and tracking of metrics across various data sources. It is one of the most widely used platforms with InfluxDB. There are hundreds of blogs and articles on utilizing both Grafana and InfluxDB so let’s focus on the parts that are new with 3.0.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/56BxVt4nxLyLjXG0DE85ct/bc0d27877d173087eab79eae76a9e810/FlightSQL---InfluxQL.png" alt="FlightSQL---InfluxQL" width="650" height="auto" /&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://grafana.com/grafana/plugins/influxdata-flightsql-datasource/"&gt;FlightSQL plugin&lt;/a&gt; provides a new connection method between InfluxDB and Grafana allowing users to build dashboards with native SQL. The table below provides some useful SQL queries within Grafana.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/44vuiz6GrRJ1APIQPWARwv/533825e938f2f9791fca918949d66d5d/SQL-queries-within-Grafana.png" alt="SQL-queries-within-Grafana" /&gt;&lt;/p&gt;

&lt;p&gt;Note how we can deploy &lt;code&gt;$__&lt;/code&gt; variables to make our queries dynamic. The example above shows methods for monitoring our CPU usage over time and the last known total memory reading.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/3FzvlNYQ1GlAkFKl9c49og/743fc388d21e63421172a2d9846dfec9/memory_reading.png" alt="memory reading" /&gt;&lt;/p&gt;

&lt;p&gt;You can find the full dashboard &lt;a href="https://github.com/InfluxCommunity/InfluxDB-3-Quick-Starts"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id="opentelemetry"&gt;OpenTelemetry&lt;/h3&gt;

&lt;p&gt;The last point I wanted to touch on is OpenTelemetry. InfluxDB 3.0 provides one datastore for metrics, logs, and traces. We are working hard to provide the integrations required to make InfluxDB a plug-and-play solution for your OpenTelemetry stack. The ultimate goal is to provide the ability to visualize and inspect traces alongside metrics using a single pane of glass through Grafana.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/2JrMtpDuCu1Fx4zZ0vnQ8G/29e6eaaec42c02513a347eef89df4cb9/OpenTelemetry.png" alt="OpenTelemetry" /&gt;&lt;/p&gt;

&lt;p&gt;We use Killercoda to provide an online interactive demo, which you can try out &lt;a href="https://killercoda.com/influxdata/course/demos/otel"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="the-finishing-touch"&gt;The finishing touch&lt;/h2&gt;

&lt;p&gt;Our three-step milestones to building an infrastructure monitoring platform.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/2TtqPAjLgWogprtqscovVT/89c4bec811b97b8ba36be56223a94b7f/three-step-milestones-finishing-touch.png" alt="three-step-milestones-finishing-touch" /&gt;&lt;/p&gt;

&lt;p&gt;I took the liberty of adding some further integrations to the Data Action list. Let’s conclude by applying this to our Whisper GPT platform.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/45BpGOOdPGHcyG1BCYKdJp/255a89940dadee60b521d0feb9592d3a/Wisper-GPT-Solution.png" alt="Wisper-GPT-Solution" /&gt;&lt;/p&gt;

&lt;p&gt;Through the integration of Telegraf, InfluxDB, and Grafana (aka the TIG stack), we architected a scalable solution adept at collecting, storing, and processing infrastructure data across diverse domains.&lt;/p&gt;

&lt;p&gt;It’s my hope that this blog not only enlightens you about the journey of InfluxDB 3.0 and infrastructure monitoring, but also kindles your interest in the expansive world of Open Source. Open architecture offers a wealth of benefits, and the deeper you dive the more you will find. If you have any questions or comments on InfluxDB, Telegraf, or infrastructure monitoring in general please do not hesitate to reach out to me via &lt;a href="https://www.influxdata.com/slack"&gt;Slack&lt;/a&gt;. I would love to hear from you.&lt;/p&gt;
</description>
      <pubDate>Tue, 29 Aug 2023 07:35:00 +0000</pubDate>
      <link>https://www.influxdata.com/blog/infrastructure-monitoring-basics-telegraf-influxdb-grafana/</link>
      <guid isPermaLink="true">https://www.influxdata.com/blog/infrastructure-monitoring-basics-telegraf-influxdb-grafana/</guid>
      <category>Product</category>
      <author>Jay Clifford (InfluxData)</author>
    </item>
    <item>
      <title>Tutorial: Modifying Grafana's Source Code</title>
      <description>
&lt;p&gt;&lt;em&gt;This article was originally published on &lt;a href="https://dev.to/jayclifford345/tutorial-modifying-grafanas-source-code-3p0f"&gt;dev.to&lt;/a&gt; and is reposted here with permission.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id="a-story-of-exploration-and-guesswork"&gt;A story of exploration and guesswork&lt;/h2&gt;

&lt;p&gt;So this blog is a little different from my usual tutorials…&lt;/p&gt;

&lt;div class="youtube-container"&gt;
  &lt;iframe class="responsive-iframe" src="https://www.youtube.com/embed/xZ9gwBO3TMM" title="InfluxDays Virtual Experience NA 2020"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;A little background: I have been working with Jacob Marble to test and “demo-fy” his work with InfluxDB 3.0 and the OpenTelemetry ecosystem (If you would like to learn more, I highly recommend checking out this &lt;a href="https://www.influxdata.com/blog/opentelemetry-tutorial-collect-traces-logs-metrics-influxdb-3-0-jaeger-grafana/"&gt;blog&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;During the project, we identified a need to enable specific Grafana features for InfluxDB data sources, particularly the trace to logs functionality. Grafana is an open source platform, and one of its major advantages is the ability to modify its source code to suit our unique requirements. However, diving into the codebase of such a robust tool can be overwhelming, even for the most seasoned developers.&lt;/p&gt;

&lt;p&gt;Despite the complexity, we embraced the challenge and dove headfirst into Grafana’s source code. We tumbled, we stumbled, and we learned a great deal along the way. And now, having successfully modified Grafana to meet our specific project needs, I believe it’s time to share this acquired knowledge with you all.&lt;/p&gt;

&lt;p&gt;The purpose of this blog is not just to provide you with a step-by-step guide for tweaking Grafana’s source code, but also to inspire you to explore and adapt open source projects to your needs. It’s about imparting a method and a mindset, cultivating a culture of curiosity, and encouraging more hands-on learning and problem-solving.&lt;/p&gt;

&lt;p&gt;I hope that this guide inspires you to modify Grafana’s source code for your projects, thereby expanding the horizons of what’s possible with open source platforms. It’s time to roll up your sleeves and venture into the depths of Grafana’s code.&lt;/p&gt;

&lt;h2 id="the-problem"&gt;The problem&lt;/h2&gt;

&lt;p&gt;So our problem lies within the &lt;a href="https://grafana.com/docs/grafana/latest/panels-visualizations/visualizations/traces/"&gt;Trace visualization&lt;/a&gt; of Grafana.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/4zoKkDF6XHLGpqxyODIzXo/3969cd81fc73df4ec2c4db5742b46a67/Trace_visualization_of_Grafana.png" alt="Trace visualization of Grafana" /&gt;&lt;/p&gt;

&lt;p&gt;As you can see the visualization performs rather well with InfluxDB except for one disabled button: &lt;strong&gt;Logs for this span&lt;/strong&gt;. If we don’t configure a log data source with our trace data source (in this case, Jaeger with InfluxDB 3.0 acting as the &lt;a href="https://www.jaegertracing.io/docs/next-release/deployment/#sidecar-model"&gt;gRPC storage engine&lt;/a&gt;), then Grafana automatically disables this button. Grafana usually represents a log data source by default using the &lt;a href="https://grafana.com/docs/grafana/latest/explore/logs-integration/"&gt;log explorer interface&lt;/a&gt;. Common log data sources include &lt;a href="https://grafana.com/oss/loki/"&gt;Loki&lt;/a&gt;, &lt;a href="https://opensearch.org/"&gt;OpenSearch&lt;/a&gt;, and &lt;a href="https://www.elastic.co/"&gt;Elasticsearch&lt;/a&gt;. So let’s head across to the Jaeger data source and configure that…&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/3kSxBQlSucJRj8a2FasiRh/0ad7442d30c47380fcb60e3333d9fbea/Connections-data_source.png" alt="Connections-data source" /&gt;&lt;/p&gt;

&lt;p&gt;You can navigate data sources via &lt;strong&gt;Connections -&amp;gt; Data Sources&lt;/strong&gt;. We currently have three data sources configured: FlightSQL, InfluxDB, and Jaeger. If we open the Jaeger configuration and navigate to the &lt;strong&gt;Trace to Logs&lt;/strong&gt; section we want to be able to select either InfluxDB or FlightSQL as our Data source.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/6jTO46BmplTdxeRkjvvFzG/d2feb512c6401fb588b660a7be2ebd8a/Trace_to_logs_-_Grafana.png" alt="Trace to logs - Grafana" /&gt;&lt;/p&gt;

&lt;p&gt;Houston, we have a problem. It appears Grafana doesn’t recognize InfluxDB as a log data source. Fair enough. InfluxDB only recently became a viable option for logs. So, what are our options?&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;We lie down, accept the issue, and hope that in the future this feature becomes generic enough to support more data sources.&lt;/li&gt;
  &lt;li&gt;Take action and make the change ourselves.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Well, by now you know what option we chose.&lt;/p&gt;

&lt;h2 id="the-solution"&gt;The solution&lt;/h2&gt;

&lt;p&gt;This section summarizes the steps I took to discover the changes I needed to make, how to implement the changes for your own data source, and, finally, how to build your own custom build of Grafana OSS.&lt;/p&gt;

&lt;h3 id="discovery"&gt;Discovery&lt;/h3&gt;

&lt;p&gt;So the first step is to understand where to even begin. Grafana is a huge open source platform with many components so I needed to narrow down the search. So the first thing I did was search the Grafana repository for signs of life.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/3zp7XFUjjSuGS4DSAFpSYq/ca48c9b4dd87d2223f859ec3c740423c/Discovery.png" alt="Discovery" /&gt;&lt;/p&gt;

&lt;p&gt;As you can see I made this little discovery by using the keyword trace, which led me to the directory &lt;strong&gt;TraceToLogs&lt;/strong&gt;. This led me to this section of code within &lt;a href="https://github.com/grafana/grafana/blob/main/public/app/core/components/TraceToLogs/TraceToLogsSettings.tsx"&gt;&lt;strong&gt;TraceToLogsSettings.tsx&lt;/strong&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-typescript"&gt;export function TraceToLogsSettings({ options, onOptionsChange }: Props) {
  const supportedDataSourceTypes = [
    'loki',
    'elasticsearch',
    'grafana-splunk-datasource', // external
    'grafana-opensearch-datasource', // external
    'grafana-falconlogscale-datasource', // external
    'googlecloud-logging-datasource', // external
  ];&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This section of code seems to create a static list of data sources supported by the Trace to Logs feature. We can confirm this by some of the common suspects within the list (Loki, Elasticsearch, etc.). Based on this finding, our first alteration to the Grafana source code is to add our data sources to this list.&lt;/p&gt;

&lt;p&gt;Now, as the coding pessimist that I am, I knew this probably wouldn’t be the only change we needed to make but it’s a good place to start. So, I did the following:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;I forked the Grafana repo&lt;/li&gt;
  &lt;li&gt;Cloned the repo:&lt;/li&gt;
&lt;/ol&gt;

&lt;pre&gt;&lt;code class="language-bash"&gt;git clone https://github.com/InfluxCommunity/grafana&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Before I made those modifications I wanted to do some more searching to see if there were any other changes I should make. One line stood out to me in &lt;strong&gt;TraceToLogsSettings&lt;/strong&gt; file:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-typescript"&gt;const updateTracesToLogs = useCallback(
    (value: Partial&amp;lt;TraceToLogsOptionsV2&amp;gt;) =&amp;gt; {
      // Cannot use updateDatasourcePluginJsonDataOption here as we need to update 2 keys, and they would overwrite each
      // other as updateDatasourcePluginJsonDataOption isn't synchronized
      onOptionsChange({
        ...options,
        jsonData: {
          ...options.jsonData,
          tracesToLogsV2: {
            ...traceToLogs,
            ...value,
          },
          tracesToLogs: undefined,
        },
      });
    },
    [onOptionsChange, options, traceToLogs]
  );&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It was &lt;strong&gt;TraceToLogsOptionsV2&lt;/strong&gt;. When I searched for places where Grafana used this interface, I found the following entry.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/4qFUJipJ4cX7iPqU4nWbvD/a42006a8194945626a534da3006440e0/TraceToLogsOptionsV2.png" alt="TraceToLogsOptionsV2" width="350" height="auto" /&gt;&lt;/p&gt;

&lt;p&gt;It appears we might also have work to do in the &lt;a href="https://github.com/grafana/grafana/blob/main/public/app/features/explore/TraceView/createSpanLink.tsx#L332"&gt;&lt;strong&gt;createSpanLink.tsx&lt;/strong&gt;&lt;/a&gt; file. Within this section I found the following piece of code. At this point, my question was “what exactly is this code doing?”&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/5BrqpqMCichU6kNyKD5JWG/b2a1573192cb3db7833167511d376d8c/case_statement.png" alt="case statement" /&gt;&lt;/p&gt;

&lt;p&gt;To cut a long story short, the case statement essentially tells the trace visualization to check the defined log data source (if any) and to define a query interface relevant to that data source. If the specified data source is not found within this case statement, then Grafana simply disables the button. This meant that changing the original file won’t be enough as we suspected.&lt;/p&gt;

&lt;p&gt;Okay, with our investigation complete, let’s move on to the code changes.&lt;/p&gt;

&lt;h3 id="modification"&gt;Modification&lt;/h3&gt;

&lt;p&gt;We have two files to modify:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href="https://github.com/grafana/grafana/blob/main/public/app/core/components/TraceToLogs/TraceToLogsSettings.tsx"&gt;&lt;strong&gt;TraceToLogsSettings.tsx&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://github.com/grafana/grafana/blob/main/public/app/features/explore/TraceView/createSpanLink.tsx#L332"&gt;&lt;strong&gt;createSpanLink.tsx&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s start with the simplest to tackle and go from there.&lt;/p&gt;

&lt;h4 id="tracetologssettings"&gt;TraceToLogsSettings&lt;/h4&gt;

&lt;p&gt;This file was relatively simple to change. All we needed to do was modify the static list of supported log input sources like so:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-typescript"&gt;export function TraceToLogsSettings({ options, onOptionsChange }: Props) {
  const supportedDataSourceTypes = [
    'loki',
    'elasticsearch',
    'grafana-splunk-datasource', // external
    'grafana-opensearch-datasource', // external
    'grafana-falconlogscale-datasource', // external
    'googlecloud-logging-datasource', // external
    'influxdata-flightsql-datasource', // external
    'influxdb', // external
  ];&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you can see, I added two data sources. I ran a quick build of the Grafana project to see how this affected our data source configuration (we will discuss how to build at the end).&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/77fjtMzolNrkY8dbn1V3fQ/a2daad9b5c1ec2e2ae2fa755b875caff/Trace-to-logs-influxdb-v1.png" alt="Trace-to-logs-influxdb-v1" /&gt;&lt;/p&gt;

&lt;p&gt;Hey presto! We have a result. Now, this still didn’t enable the button within our Trace View but we already knew this would require more work.&lt;/p&gt;

&lt;h4 id="createspanlink"&gt;createSpanLink&lt;/h4&gt;

&lt;p&gt;Now, let’s move on to the meat of our modification. For the record, I am not a TypeScript developer. What I do know is that the file has a whole bunch of examples we can use to attempt a blind copy-and-paste job with a few modifications. I ended up doing this for both plugins but to keep the blog short we will focus on the InfluxDB official plugin.&lt;/p&gt;

&lt;p&gt;My hypothesis was to use the Grafana Loki interface as the basis for the InfluxDB interface. The first included adding data source types:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-typescript"&gt;import { LokiQuery } from '../../../plugins/datasource/loki/types';
import { InfluxQuery } from '../../../plugins/datasource/influxdb/types';&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These are easy to locate when Grafana has an official plugin for your data source since it’s embedded within the official repository. For our community plugin I had two options: define a static interface within the file or provide more query parameters. I chose the latter.&lt;/p&gt;

&lt;p&gt;The next step was to modify the case statement:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-typescript"&gt;// TODO: This should eventually move into specific data sources and added to the data frame as we no longer use the
    //  deprecated blob format and we can map the link easily in data frame.
    if (logsDataSourceSettings &amp;amp;&amp;amp; traceToLogsOptions) {
      const customQuery = traceToLogsOptions.customQuery ? traceToLogsOptions.query : undefined;
      const tagsToUse =
        traceToLogsOptions.tags &amp;amp;&amp;amp; traceToLogsOptions.tags.length &amp;gt; 0 ? traceToLogsOptions.tags : defaultKeys;
      switch (logsDataSourceSettings?.type) {
        case 'loki':
          tags = getFormattedTags(span, tagsToUse);
          query = getQueryForLoki(span, traceToLogsOptions, tags, customQuery);
          break;
        case 'grafana-splunk-datasource':
          tags = getFormattedTags(span, tagsToUse, { joinBy: ' ' });
          query = getQueryForSplunk(span, traceToLogsOptions, tags, customQuery);
          break;
        case 'influxdata-flightsql-datasource':
            tags = getFormattedTags(span, tagsToUse, { joinBy: ' OR ' });
            query = getQueryFlightSQL(span, traceToLogsOptions, tags, customQuery);
          break;
        case 'influxdb':
            tags = getFormattedTags(span, tagsToUse, { joinBy: ' OR ' });
            query = getQueryForInfluxQL(span, traceToLogsOptions, tags, customQuery);
          break;
        case 'elasticsearch':
        case 'grafana-opensearch-datasource':
          tags = getFormattedTags(span, tagsToUse, { labelValueSign: ':', joinBy: ' AND ' });
          query = getQueryForElasticsearchOrOpensearch(span, traceToLogsOptions, tags, customQuery);
          break;
        case 'grafana-falconlogscale-datasource':
          tags = getFormattedTags(span, tagsToUse, { joinBy: ' OR ' });
          query = getQueryForFalconLogScale(span, traceToLogsOptions, tags, customQuery);
          break;
        case 'googlecloud-logging-datasource':
          tags = getFormattedTags(span, tagsToUse, { joinBy: ' AND ' });
          query = getQueryForGoogleCloudLogging(span, traceToLogsOptions, tags, customQuery);
      }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you can see I added two new cases:  &lt;code class="language-typescript"&gt;influxdata-flightsql-datasource&lt;/code&gt; and &lt;code class="language-typescript"&gt;influxdb&lt;/code&gt;. Then, I copied the two function calls within the case from Loki: &lt;code class="language-typescript"&gt;getFormattedTags&lt;/code&gt; and &lt;code class="language-typescript"&gt;getQueryFor&lt;/code&gt;. I determined that I could leave &lt;code class="language-typescript"&gt;getFormattedTags&lt;/code&gt; alone because it appeared to be the same for the majority of the cases. However, I still needed to define my own &lt;code class="language-typescript"&gt;getQueryFor&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;Let’s take a look at the new &lt;code class="language-typescript"&gt;getQueryForInfluxQL&lt;/code&gt; function that’s called in the &lt;code class="language-typescript"&gt;influxdb&lt;/code&gt; case statement:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-typescript"&gt;function getQueryForInfluxQL(
  span: TraceSpan,
  options: TraceToLogsOptionsV2,
  tags: string,
  customQuery?: string
): InfluxQuery | undefined {
  const { filterByTraceID, filterBySpanID } = options;

  if (customQuery) {
    return {
      refId: '',
      rawQuery: true,
      query: customQuery,
      resultFormat: 'logs',
    };
  }

  let query = 'SELECT time, "severity_text", body, attributes FROM logs WHERE time &amp;gt;=${__from}ms AND time &amp;lt;=${__to}ms';

  if (filterByTraceID &amp;amp;&amp;amp; span.traceID &amp;amp;&amp;amp; filterBySpanID &amp;amp;&amp;amp; span.spanID) {
            query = 'SELECT time, "severity_text", body, attributes FROM logs WHERE "trace_id"=\'${__span.traceId}\' AND "span_id"=\'${__span.spanId}\' AND time &amp;gt;=${__from}ms AND time &amp;lt;=${__to}ms';
    } else if (filterByTraceID &amp;amp;&amp;amp; span.traceID) {
            query = 'SELECT time, "severity_text", body, attributes FROM logs WHERE "trace_id"=\'${__span.traceId}\' AND time &amp;gt;=${__from}ms AND time &amp;lt;=${__to}ms';
    } else if (filterBySpanID &amp;amp;&amp;amp; span.spanID) {
            query = 'SELECT time, "severity_text", body, attributes FROM logs WHERE "span_id"=\'${__span.spanId}\' AND time &amp;gt;=${__from}ms AND time &amp;lt;=${__to}ms';
  }

  return {
    refId: '',
    rawQuery: true,
    query: query,
    resultFormat: 'logs',
  };
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There is quite a lot here, but let me highlight the important parts. First of all, I started with an exact copy of the Loki function. Then, I made the following changes:&lt;/p&gt;

&lt;ol&gt;
&lt;li style="padding-bottom: 10px;"&gt;I changed the return interface from &lt;code class="language-markup"&gt;LokiQuery | undefined&lt;/code&gt; to &lt;code class="language-markup"&gt;InfluxQuery | undefined&lt;/code&gt;. This is the data source type we imported earlier.&lt;/li&gt;

&lt;li style="padding-bottom: 10px;"&gt; Next, I focused on the return payload. After some digging in the InfluxQuery type file, I came up with this:

&lt;pre&gt;&lt;code class="language-typescript"&gt;return {
    refId: '',
    rawQuery: true,
    query: query,
    resultFormat: 'logs',
  };&lt;/code&gt;&lt;/pre&gt;

The InfluxDB data source had a resultFormat parameter which allowed me to define the result format (usually metrics). This also informed me that the data source expected a raw query rather than an expression.
  &lt;/li&gt;

&lt;li style="padding-bottom: 10px;"&gt; Lastly, I defined the queries that would run when the user clicked the button. These depended on what filter features the user toggled within the data source settings (filter by traceID, spanID or both). I modified the &lt;code class="language-typescript"&gt;if&lt;/code&gt; statement defined within the Loki function and constructed static InfluxQL queries. From there, I used the Grafana placeholder variables found within other data sources to make the queries dynamic. Here is an example:

&lt;pre&gt;&lt;code class="language-typescript"&gt;if (filterByTraceID &amp;amp;&amp;amp; span.traceID &amp;amp;&amp;amp; filterBySpanID &amp;amp;&amp;amp; span.spanID) {
            query = 'SELECT time, "severity_text", body, attributes FROM logs WHERE "trace_id"=\'${__span.traceId}\' AND "span_id"=\'${__span.spanId}\' AND time &amp;gt;=${__from}ms AND time &amp;lt;=${__to}ms';&lt;/code&gt;&lt;/pre&gt;

Full disclosure, it took me a good minute to find out about the &lt;code class="language-typescript"&gt;&amp;gt;=${__from}ms&lt;/code&gt;  and &lt;code class="language-typescript"&gt;&amp;lt;=${__to}ms&lt;/code&gt;. This ended up being a brute force build and error case.
  &lt;/li&gt;
 &lt;/ol&gt;

&lt;h3 id="building"&gt;Building&lt;/h3&gt;

&lt;p&gt;Phew! We’re past the hard bit. Now onto the build process. I have quite a few years of experience with Docker, so this part was stress-free for me, but I imagine it could be daunting for new Docker users. Luckily, Grafana has some easy-to-follow &lt;a href="https://github.com/grafana/grafana/blob/main/contribute/developer-guide.md"&gt;documentation&lt;/a&gt; for the task. To paraphrase, these are the steps:&lt;/p&gt;

&lt;ol&gt;
  &lt;li style="padding-bottom: 10px;"&gt;  Run the following build command (this can take a while and make sure your docker VM has enough memory if using macOS or Windows)

&lt;pre&gt;&lt;code class="language-bash"&gt;make build-docker-full&lt;/code&gt;&lt;/pre&gt;
 &lt;/li&gt;

&lt;li style="padding-bottom: 10px;"&gt; The build process produces a Docker image called: &lt;b&gt;grafana/grafana-oss:dev&lt;/b&gt;. We could just use this image, but as a formality, I like to retag the image and push it to my Docker registry.

&lt;pre&gt;&lt;code class="language-bash"&gt;docker tag grafana/grafana-oss:dev jaymand13/grafana-oss:dev2
docker push jaymand13/grafana-oss:dev2&lt;/code&gt;&lt;/pre&gt;

This way I have checkpoints when I am brute forcing changes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There we have it! A fully baked Grafana dev image to try out with our changes.&lt;/p&gt;

&lt;h2 id="the-results-and-conclusion"&gt;The results and conclusion&lt;/h2&gt;

&lt;p&gt;So after investigating, making the changes, and building our new Grafana container, let’s take a look at our results:&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/1i882CV7mWScQZNOS5mWIm/7fe6e2ce18177162b10ea15655e685b2/Logs_for_this_span.png" alt="Logs for this span" /&gt;&lt;/p&gt;

&lt;p&gt;With our changes, the &lt;strong&gt;Logs for this span&lt;/strong&gt; button is now active. We also have this neat little Log button that appears next to each span. A confession: the blue &lt;strong&gt;Logs for this span&lt;/strong&gt; button currently only works within the Grafana Explorer tab, but the new &lt;strong&gt;Log&lt;/strong&gt; link works within our dashboard.&lt;/p&gt;

&lt;p&gt;To quickly explain the differences, users build custom Grafana Dashboards and can include 1 or many data sources with a variety of different visualizations. Data Explorers, on the other hand, provide an interface for drill-down and investigation activities like you see in the screenshot above. Still, it’s not a huge problem compared to how little we needed to change to get here.&lt;/p&gt;

&lt;p&gt;And so, we’ve reached the end of our dive into the intricacies of modifying Grafana’s source code. Over the course of this tutorial, I hope you’ve not only gained a practical understanding of how to customize Grafana for your specific requirements, but also an appreciation for the flexibility and potential of open source platforms in general.&lt;/p&gt;

&lt;p&gt;Remember, in the realm of open source, there’s no limit to how much we can tweak, adjust, and reimagine to suit our needs. I hope this guide serves you well as you delve deeper into your own projects, and that it brings you one step closer to mastering the powerful tool that is Grafana. For me, my journey continues as I now plan to add exemplar support to this OSS build. If you would like to try this out yourself you can find the OpenTelemetry example &lt;a href="https://github.com/InfluxCommunity/opentelemetry-demo"&gt;here&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Fri, 25 Aug 2023 07:35:00 +0000</pubDate>
      <link>https://www.influxdata.com/blog/tutorial-modifying-grafana-source-code/</link>
      <guid isPermaLink="true">https://www.influxdata.com/blog/tutorial-modifying-grafana-source-code/</guid>
      <category>Developer</category>
      <author>Jay Clifford (InfluxData)</author>
    </item>
    <item>
      <title>Client Library Deep Dive: Python (Part 2)</title>
      <description>&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/81ItCagU4rLxIWrSsMcSG/5a7cbc2e4fff2474ab2f3eb87bf6d964/InfluxDB-3-Python.png" alt="InfluxDB-3-Python" /&gt;&lt;/p&gt;

&lt;h2 id="working-with-the-new-influxdb-30-python-cli-and-client-library"&gt;Working with the new InfluxDB 3.0 Python CLI and Client Library&lt;/h2&gt;

&lt;p&gt;Okay, we are back for Part 2! &lt;a href="https://www.influxdata.com/blog/client-library-deep-dive-python-part-1/"&gt;Last time&lt;/a&gt; we discussed the new community Python library for InfluxDB 3.0. If you missed it, you can also watch it in video form.&lt;/p&gt;

&lt;div style="padding:56.25% 0 0 0;position:relative;"&gt;&lt;iframe src="https://player.vimeo.com/video/850608972?h=2c80011e5d&amp;amp;badge=0&amp;amp;autopause=0&amp;amp;player_id=0&amp;amp;app_id=58479" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen="" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="Getting Started: InfluxDB 3.0 Python Client"&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;script src="https://player.vimeo.com/api/player.js"&gt;&lt;/script&gt;

&lt;p&gt;&lt;br /&gt;Now for Part 2, let’s talk about a bolt-on application that uses the client library as the core of its development, the &lt;a href="https://github.com/InfluxCommunity/influxdb3-python-cli"&gt;InfluxDB 3.0 Python CLI&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="python-cli"&gt;Python CLI&lt;/h2&gt;

&lt;p&gt;Okay, so following the same format as before, what were the reasons for building the CLI? Well, there are two primary reasons:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;We wanted to give users a data browsing tool that leveraged the new Flight endpoint. Python gave us the opportunity to prototype fast before we invested work in a more robust CLI offering. It also allowed us to leverage some interesting data manipulation libraries that could extend the scope of the Python CLI.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We wanted a robust way to test the newly created &lt;a href="https://github.com/InfluxCommunity/influxdb3-python"&gt;InfluxDB 3.0 Python Client library&lt;/a&gt;, as you will see most of the tooling and functionality in use.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id="install"&gt;Install&lt;/h3&gt;

&lt;p&gt;Let’s talk about the installation process because, I must admit, Python doesn’t provide the most user-friendly packaging and deployment methods unless you use it daily. I recommend installing the CLI in a Python Virtual Environment first for test purposes:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-bash"&gt;$ python3 -m venv ./.venv
$ source .venv/bin/activate
$ pip install –upgrade pip
$ pip install influxdb3-python-cli&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This set of commands creates our Virtual Python Environment, activates it, updates our Python package installer, and finally installs the new CLI.&lt;/p&gt;

&lt;p&gt;If you would like to graduate from a Python Virtual Environment and move the CLI to your path, you can do so with a sudo install (You have to be careful here not to cause permission issues with packages):&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-bash"&gt;sudo python3 -m pip install influxdb3-python-cli&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="creating-a-cli-config"&gt;Creating a CLI config&lt;/h3&gt;

&lt;p&gt;The first thing you want to do is create a connection config. This feature acts like the current InfluxDB influx CLI by saving your connection credentials for InfluxDB to use later.&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-bash"&gt;influx3 create config \
--name="poke-dex" \
--database="pokemon-codex" \
--host="us-east-1-1.aws.cloud2.influxdata.com" \
--token="&amp;lt;your token&amp;gt;" \
--org="&amp;lt;your org ID&amp;gt;"&lt;/code&gt;&lt;/pre&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;–name&lt;/td&gt;
      &lt;td&gt;Name to describe your connection config. This must be unique.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;–token&lt;/td&gt;
      &lt;td&gt;This provides authentication for the client to read and write from InfluxDB Cloud &lt;a href="https://www.influxdata.com/products/influxdb-cloud/serverless/"&gt;Serverless&lt;/a&gt; or &lt;a href="https://www.influxdata.com/products/influxdb-cloud/dedicated/"&gt;Dedicated&lt;/a&gt;. Note: you need a token with read and write authentication if you wish to use both features.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;–host&lt;/td&gt;
      &lt;td&gt;InfluxDB host — this should only be the domain without the protocol (https://)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;–org&lt;/td&gt;
      &lt;td&gt;Cloud Serverless still requires a user’s organization ID for writing data to 3.0. Dedicated users can just use an arbitrary string.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;–database&lt;/td&gt;
      &lt;td&gt;The database you wish to query from and write to.&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h4 id="config-commands"&gt;Config commands&lt;/h4&gt;

&lt;p&gt;Config commands also exist to activate, update, delete, and list current active configs:&lt;/p&gt;

&lt;div class="table-container is-v-centered"&gt;
  &lt;table class="table is-bordered"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;influx3.py config update --name="poke-dex" --host="new-host.com"&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;td&gt;&lt;span style="font-weight: 400;"&gt;The update subcommand updates an existing configuration. The --name parameter is required to specify which configuration to update. All other parameters (--host, --token, --database, --org, --active) are optional.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;influx3.py config use --name="poke-dex"&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;td&gt;&lt;span style="font-weight: 400;"&gt;The use subcommand sets a specific configuration as the active one. The --name parameter is required to specify which configuration to use.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;influx3.py config delete --name="poke-dex"&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;td&gt;&lt;span style="font-weight: 400;"&gt;The delete subcommand deletes a configuration. The --name parameter is required to specify which configuration to delete.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;influx3.py config list&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;td&gt;&lt;span style="font-weight: 400;"&gt;The list subcommand lists all the configurations.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
 &lt;/div&gt;

&lt;h3 id="writing-and-querying"&gt;Writing and querying&lt;/h3&gt;

&lt;p&gt;You can use the CLI to either directly call the application, followed by the commands you wish to run, or run it through an interactive &lt;a href="https://www.digitalocean.com/community/tutorials/what-is-repl"&gt;REPL&lt;/a&gt;. I personally believe the REPL approach provides a better flow, so let’s demo some of the features.&lt;/p&gt;

&lt;p&gt;Once you created your config you simply enter the following to activate the REPL:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-bash"&gt;influx3&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which leads to:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-bash"&gt;influx3
InfluxDB 3.0 CLI.

(&amp;gt;)&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id="query"&gt;Query&lt;/h4&gt;

&lt;p&gt;Let’s first take a look at the query options. Within the REPL you have 3 query options: SQL, InfluxQL, and chatGPT (more on this later). Let’s drop into the SQL REPL and run a basic query against the Trainer data we generated in the previous blog:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-bash"&gt;InfluxDB 3.0 CLI.

(&amp;gt;) sql
(sql &amp;gt;) SELECT * FROM caught&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now I wouldn’t normally recommend querying without some form of time-based WHERE clause, but I wanted to highlight how the CLI can handle large datasets. It uses &lt;code class="language-bash"&gt;mode = chunk&lt;/code&gt; from the Python Client Library to break large datasets into manageable Arrow batches. From there we have three options.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;We can either hit &lt;strong&gt;TAB&lt;/strong&gt; to see the next portion of data, if one exists.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Press &lt;strong&gt;F&lt;/strong&gt; to save the current Arrow batch to a file type of our choosing (JSON, CSV, Parquet, ORC, Feather).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Press &lt;strong&gt;CTRL-C&lt;/strong&gt; to return back to the SQL REPL.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s take a look at the option 2:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-bash"&gt;| 3961 |       82 | Venusaur                  |        83 |   80 | 0003 |      12 |     7 |      80 | 2023-07-06 13:41:36.588000 | ash       | Grass    | Poison   |
| 3962 |       64 | Dratini                   |        45 |   41 | 0147 |       6 |     7 |      50 | 2023-07-06 14:30:32.519000 | jessie    | Dragon   |          |

Press TAB to fetch next chunk of data, or F to save current chunk to a file
Enter the file name with full path (e.g. /home/user/sample.json): ~/Desktop/all-trainer-data.csv
Data saved to ~/Desktop/all-trainer-data.csv.&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here is a sample of the CSV file created:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-csv"&gt;"attack","caught","defense","hp","id","level","num","speed","time","trainer","type1","type2"
49,"Bulbasaur",49,45,"0001",12,"1",45,2023-07-06 14:30:41.886000000,"ash","Grass","Poison"
62,"Ivysaur",63,60,"0002",7,"1",60,2023-07-06 14:30:32.519000000,"ash","Grass","Poison"
62,"Ivysaur",63,60,"0002",8,"1",60,2023-07-06 14:30:38.519000000,"ash","Grass","Poison"&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once we reach the end of our dataset, it prompts us to press &lt;strong&gt;ENTER&lt;/strong&gt; to drop back into the SQL REPL. Just remember if you feel like you’re pressing &lt;strong&gt;TAB&lt;/strong&gt; forever, you can always drop out of the query with &lt;strong&gt;CTRL-C&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now, let’s look at a more interesting example with the InfluxQL REPL:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-bash"&gt;(sql &amp;gt;) exit
(&amp;gt;) influxql
(influxql &amp;gt;) SELECT count(caught) FROM caught WHERE time &amp;gt; now() - 2d GROUP BY trainer
|    | iox::measurement   | time                | trainer   |   count |
|---:|:-------------------|:--------------------|:----------|--------:|
|  0 | caught             | 1970-01-01 00:00:00 | ash       |     625 |
|  1 | caught             | 1970-01-01 00:00:00 | brock     |     673 |
|  2 | caught             | 1970-01-01 00:00:00 | gary      |     645 |
|  3 | caught             | 1970-01-01 00:00:00 | james     |     664 |
|  4 | caught             | 1970-01-01 00:00:00 | jessie    |     663 |
|  5 | caught             | 1970-01-01 00:00:00 | misty     |     693 |

(influxql &amp;gt;) SELECT count(caught) FROM caught WHERE time &amp;gt; now() - 2d  GROUP BY time(1d),trainer ORDER BY time
|    | iox::measurement   | time                | trainer   |   count |
|---:|:-------------------|:--------------------|:----------|--------:|
|  0 | caught             | 2023-07-05 00:00:00 | ash       |     nan |
|  1 | caught             | 2023-07-06 00:00:00 | ash       |     625 |
|  2 | caught             | 2023-07-07 00:00:00 | ash       |     148 |
|  3 | caught             | 2023-07-05 00:00:00 | brock     |     nan |
|  4 | caught             | 2023-07-06 00:00:00 | brock     |     673 |
|  5 | caught             | 2023-07-07 00:00:00 | brock     |     180 |
|  6 | caught             | 2023-07-05 00:00:00 | gary      |     nan |
|  7 | caught             | 2023-07-06 00:00:00 | gary      |     645 |
|  8 | caught             | 2023-07-07 00:00:00 | gary      |     155 |
|  9 | caught             | 2023-07-05 00:00:00 | james     |     nan |
| 10 | caught             | 2023-07-06 00:00:00 | james     |     664 |
| 11 | caught             | 2023-07-07 00:00:00 | james     |     157 |
| 12 | caught             | 2023-07-05 00:00:00 | jessie    |     nan |
| 13 | caught             | 2023-07-06 00:00:00 | jessie    |     663 |
| 14 | caught             | 2023-07-07 00:00:00 | jessie    |     144 |
| 15 | caught             | 2023-07-05 00:00:00 | misty     |     nan |
| 16 | caught             | 2023-07-06 00:00:00 | misty     |     693 |
| 17 | caught             | 2023-07-07 00:00:00 | misty     |     178 |&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We will save this one as a &lt;a href="https://www.influxdata.com/glossary/apache-parquet/"&gt;Parquet&lt;/a&gt; file for later.&lt;/p&gt;

&lt;h4 id="write"&gt;Write&lt;/h4&gt;

&lt;p&gt;Moving on from using the CLI for querying, let’s talk about the write functionality. Now, this feature set isn’t as fleshed out as I would like it to be but it covers the basics. We can drop into the write REPL and write data to InfluxDB using line protocol like so:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-bash"&gt;(influxql &amp;gt;) exit
(&amp;gt;) write
(write &amp;gt;) caught,id=0115,num=1,trainer=brock attack=125i,caught="KangaskhanMega Kangaskhan",defense=100i,hp=105i,level=13i,speed=100i,type1="Normal" 1688741473083000000&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next let’s have a look at the &lt;code class="language-bash"&gt;write_file&lt;/code&gt; feature. For this we need to drop out of the REPL entirely and use flag commands when calling ‘influx3’. Let’s load our count results into a new table:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-bash"&gt;(write &amp;gt;) exit
(&amp;gt;) exit

Exiting …

influx3 write_file --help
usage: influx3 write_file [-h] --file FILE [--measurement MEASUREMENT] --time TIME [--tags TAGS]

options:
  -h, --help            show this help message and exit
  --file FILE           the file to import
  --measurement MEASUREMENT
                        Define the name of the measurement
  --time TIME           Define the name of the time column within the file
  --tags TAGS           (optional) array of column names which are tags. Format should be: tag1,tag2

influx3 write_file --file ~/Desktop/count.parquet --time time --tags trainer --measurement summary&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here is the result:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-bash"&gt;(influxql &amp;gt;) SELECT count, trainer, time  FROM summary
|    | iox::measurement   | time                |   count | trainer   |
|---:|:-------------------|:--------------------|--------:|:----------|
|  0 | summary            | 2023-07-05 00:00:00 |     nan | ash       |
|  1 | summary            | 2023-07-05 00:00:00 |     nan | brock     |
|  2 | summary            | 2023-07-05 00:00:00 |     nan | gary      |
|  3 | summary            | 2023-07-05 00:00:00 |     nan | james     |
|  4 | summary            | 2023-07-05 00:00:00 |     nan | jessie    |
|  5 | summary            | 2023-07-05 00:00:00 |     nan | misty     |
|  6 | summary            | 2023-07-06 00:00:00 |     625 | ash       |
|  7 | summary            | 2023-07-06 00:00:00 |     673 | brock     |
|  8 | summary            | 2023-07-06 00:00:00 |     645 | gary      |
|  9 | summary            | 2023-07-06 00:00:00 |     664 | james     |
| 10 | summary            | 2023-07-06 00:00:00 |     663 | jessie    |
| 11 | summary            | 2023-07-06 00:00:00 |     693 | misty     |
| 12 | summary            | 2023-07-07 00:00:00 |     148 | ash       |
| 13 | summary            | 2023-07-07 00:00:00 |     180 | brock     |
| 14 | summary            | 2023-07-07 00:00:00 |     155 | gary      |
| 15 | summary            | 2023-07-07 00:00:00 |     157 | james     |
| 16 | summary            | 2023-07-07 00:00:00 |     144 | jessie    |
| 17 | summary            | 2023-07-07 00:00:00 |     178 | misty     |&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="experimental-feature-chatgpt"&gt;Experimental feature (ChatGPT)&lt;/h3&gt;

&lt;p&gt;So with chatGPT and OpenAI being all the rage these days, I looked to see if their Python package could benefit the CLI. Interestingly it does… Because InfluxDB has been open source since its inception, chatGPT has become pretty well-versed in building InfluxQL queries. Take a look at this example:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-bash"&gt;(chatgpt &amp;gt;) give me a list of the top 10 caught with an attack higher than 100 from caught
Run InfluxQL query: SELECT * FROM caught WHERE attack &amp;gt; 100 LIMIT 10
|    | iox::measurement   | time                       |   attack | caught                    |   defense |   hp |   id |   level |   num |   speed | trainer   | type1    | type2   |
|---:|:-------------------|:---------------------------|---------:|:--------------------------|----------:|-----:|-----:|--------:|------:|--------:|:----------|:---------|:--------|
|  0 | caught             | 2023-07-06 13:09:36.095000 |      110 | Dodrio                    |        70 |   60 | 0085 |      19 |     1 |     100 | jessie    | Normal   | Flying  |
|  1 | caught             | 2023-07-06 13:09:36.095000 |      125 | Pinsir                    |       100 |   65 | 0127 |       6 |     1 |      85 | brock     | Bug      |         |
|  2 | caught             | 2023-07-06 13:10:53.995000 |      130 | CharizardMega Charizard X |       111 |   78 | 0006 |       6 |     1 |     100 | brock     | Fire     | Dragon  |
|  3 | caught             | 2023-07-06 13:10:53.995000 |      150 | BeedrillMega Beedrill     |        40 |   65 | 0015 |      12 |     1 |     145 | jessie    | Bug      | Poison  |
|  4 | caught             | 2023-07-06 13:10:53.995000 |      102 | Nidoking                  |        77 |   81 | 0034 |      20 |     1 |      85 | gary      | Poison   | Ground  |
|  5 | caught             | 2023-07-06 13:10:53.995000 |      105 | Primeape                  |        60 |   65 | 0057 |      16 |     1 |      95 | misty     | Fighting |         |
|  6 | caught             | 2023-07-06 13:10:53.995000 |      120 | Golem                     |       130 |   80 | 0076 |       8 |     1 |      45 | ash       | Rock     | Ground  |
|  7 | caught             | 2023-07-06 13:10:53.995000 |      105 | Muk                       |        75 |  105 | 0089 |       5 |     1 |      50 | brock     | Poison   |         |
|  8 | caught             | 2023-07-06 13:10:53.995000 |      105 | Muk                       |        75 |  105 | 0089 |      19 |     1 |      50 | james     | Poison   |         |
|  9 | caught             | 2023-07-06 13:10:53.995000 |      105 | Muk                       |        75 |  105 | 0089 |      16 |     2 |      50 | james     | Poison   |         |&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This feature currently only uses ChatGPT 3.5 and requires an OpenAPI token. If you would like instructions on how to use this feature, check out this part of the &lt;a href="https://github.com/InfluxCommunity/influxdb3-python-cli/blob/main/README.md#alpha-openai-chatgpt-support"&gt;README&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="future-hopes"&gt;Future hopes&lt;/h2&gt;

&lt;p&gt;The future is bright for the Python CLI as our development team pushes forward with tooling for InfluxDB 3.0. For now, the scope is to keep it as a bolt-on tool for Python developers and those who want an easily extendable CLI. Here is my current laundry list for the project:&lt;/p&gt;

&lt;div class="table-container is-v-centered"&gt;
  &lt;table class="table is-bordered"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="width: 70%;"&gt;Feature&lt;/th&gt;
&lt;th tyle="width: 30%;"&gt;Status&lt;/th&gt;
&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Improve OpenAI functionality:
&lt;ul&gt;
 	&lt;li&gt;Upgrade to chatgpt 4&lt;/li&gt;
 	&lt;li&gt;Add call functions&lt;/li&gt;
 	&lt;li&gt;Extend to SQL&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;td&gt;TO DO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Find a better way to package and distribute. Currently looking into Pyinstaller as an option.&lt;/td&gt;
&lt;td&gt;TO DO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extended write functionality.&lt;/td&gt;
&lt;td&gt;TO DO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Provide post query exploration support (Pandas functions)&lt;/td&gt;
&lt;td&gt;TO DO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Integrate delta sharing&lt;/td&gt;
&lt;td&gt;TO DO&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
  &lt;/div&gt;

&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;

&lt;p&gt;So there you have it, Part 2 done and dusted. I really enjoyed writing this blog series on both the Python Client Library and CLI. Having such a heavy hand in the inspection makes writing about them far more exciting and easy. I hope these blogs inspire you to join our new community-based libraries and tooling. If you want to chat about how to get involved, you can reach me via &lt;a href="https://www.influxdata.com/slack"&gt;Slack&lt;/a&gt; or &lt;a href="https://community.influxdata.com/"&gt;Discourse&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Fri, 28 Jul 2023 07:35:00 +0000</pubDate>
      <link>https://www.influxdata.com/blog/client-library-deep-dive-python-part-2/</link>
      <guid isPermaLink="true">https://www.influxdata.com/blog/client-library-deep-dive-python-part-2/</guid>
      <category>Product</category>
      <category>Developer</category>
      <author>Jay Clifford (InfluxData)</author>
    </item>
    <item>
      <title>Client Library Deep Dive: Python (Part 1)</title>
      <description>&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/81ItCagU4rLxIWrSsMcSG/5a7cbc2e4fff2474ab2f3eb87bf6d964/InfluxDB-3-Python.png" alt="InfluxDB-3-Python" /&gt;&lt;/p&gt;

&lt;h2 id="working-with-the-new-influxdb-30-python-cli-and-client-library"&gt;Working with the new InfluxDB 3.0 Python CLI and Client Library&lt;/h2&gt;

&lt;p&gt;Community Client libraries are back with &lt;a href="https://www.influxdata.com/products/influxdb-overview/"&gt;InfluxDB 3.0&lt;/a&gt;. If you would like an overview of each client library then I highly recommend checking out &lt;a href="https://www.influxdata.com/blog/querying-writing-influxdb-cloud-status-client-libraries/"&gt;Anais’s blog on their status&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this two-part blog series, we do a deep dive into the new &lt;a href="https://github.com/InfluxCommunity/influxdb3-python"&gt;Python Client Library&lt;/a&gt; and &lt;a href="https://github.com/InfluxCommunity/influxdb3-python-cli"&gt;CLI&lt;/a&gt;. By the end, you should have a good understanding of the current features, how the internals work, and my future ideas for both projects. From there my hope is that it gives you the opportunity to contribute to, and have your say in their future.&lt;/p&gt;

&lt;p&gt;In this post (Part 1), we will focus primarily on the Client Library because it underlies the Python CLI.&lt;/p&gt;

&lt;p&gt;If you prefer, you can watch this tutorial in video form.&lt;/p&gt;

&lt;div style="padding:56.25% 0 0 0;position:relative;"&gt;&lt;iframe src="https://player.vimeo.com/video/850608972?h=2c80011e5d&amp;amp;badge=0&amp;amp;autopause=0&amp;amp;player_id=0&amp;amp;app_id=58479" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen="" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="Getting Started: InfluxDB 3.0 Python Client"&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;script src="https://player.vimeo.com/api/player.js"&gt;&lt;/script&gt;

&lt;h2 id="python-client-library"&gt;Python client library&lt;/h2&gt;

&lt;p&gt;So, let’s start off with the Python client library. The scope was simple: build a library that could write to and query InfluxDB 3.0. Because the write endpoint didn’t change inInfluxDB 3.0, we could bring forward much of the functionality from the V2 library, such as batch writes, data parsing, point objects, and much more. However, on the query side of things, we had to completely remake it. We wanted to focus on the capabilities of &lt;a href="https://arrow.apache.org/docs/format/Flight.html"&gt;Arrow Flight&lt;/a&gt; and bring support for both SQL and InfluxQL-based queries. &lt;a href="https://arrow.apache.org/docs/python/index.html"&gt;PyArrow&lt;/a&gt; also opened up better ecosystem support for libraries such as Pandas and Polars, but I’ll have more on this later.&lt;/p&gt;

&lt;p&gt;Let’s build a simple Python application together that writes and queries InfluxDB 3.0.&lt;/p&gt;

&lt;h3 id="install"&gt;Install&lt;/h3&gt;

&lt;p&gt;To install the client library (I recommend making a Python Virtual Environment first):&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-bash"&gt;$ python3 -m venv ./.venv
$ source .venv/bin/activate
$ pip install –upgrade pip
$ pip install influxdb3-python&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This set of commands creates our Virtual Python Environment, activates it, updates our Python package installer, and, finally, installs the new client library.&lt;/p&gt;

&lt;h3 id="creating-a-client"&gt;Creating a client&lt;/h3&gt;

&lt;p&gt;In this section, we import our newly installed library and establish a client. I also discuss some configuration parameters and the reasoning behind them.&lt;/p&gt;

&lt;p&gt;Let’s create a main.py file with the following code:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-python"&gt;from influxdb_client_3 import InfluxDBClient3, Point
import pandas as pd
import numpy as np
import datetime

client = InfluxDBClient3( token="",
    host="eu-central-1-1.aws.cloud2.influxdata.com",
    org="6a841c0c08328fb1",
    database="pokemon-codex")&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This example shows a minimal configuration for the client. Like previous clients, it requires the following parameters:&lt;/p&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;token&lt;/td&gt;
      &lt;td&gt;This provides authentication for the client to read and write from InfluxDB Cloud &lt;a href="https://www.influxdata.com/products/influxdb-cloud/serverless/"&gt;Serverless&lt;/a&gt; or &lt;a href="https://www.influxdata.com/products/influxdb-cloud/dedicated/"&gt;Dedicated&lt;/a&gt;. Note: you need a token with read-and-write authentication if you wish to use both features.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;host&lt;/td&gt;
      &lt;td&gt;InfluxDB host — this should only be the domain without the protocol (https://)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;org&lt;/td&gt;
      &lt;td&gt;Cloud Serverless still requires the users’ organization ID for writing data to 3.0. Dedicated users can just use an arbitrary string.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;database&lt;/td&gt;
      &lt;td&gt;The database you wish to query and write from.&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;I recommend creating a client on a per-database basis, though you can update the &lt;code&gt;_database&lt;/code&gt; instance variable if you only want to create one client.&lt;/p&gt;

&lt;p&gt;Next, let’s take a look at the advanced parameters of the client:&lt;/p&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;flight_client_options&lt;/td&gt;
      &lt;td&gt;This provides access to parameters for the flight query protocol. You can find configuration options &lt;a href="https://arrow.apache.org/docs/python/generated/pyarrow.flight.FlightClient.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://github.com/InfluxCommunity/influxdb3-python/blob/main/Examples/flight_options_example.py"&gt;Example&lt;/a&gt;.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;write_client_options&lt;/td&gt;
      &lt;td&gt;This provides access to the parameters used by the V2 write client, which you can find &lt;a href="https://github.com/influxdata/influxdb-client-python#writes"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://github.com/InfluxCommunity/influxdb3-python/blob/main/Examples/batching-example.py"&gt;Example.&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;**kwargs&lt;/td&gt;
      &lt;td&gt;Lastly, this provides access to the parameters used by the V2 client, which you can find &lt;a href="https://github.com/influxdata/influxdb-client-python#via-file"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://github.com/InfluxCommunity/influxdb3-python/blob/main/Examples/batching-example.py"&gt;Example.&lt;/a&gt; (gzip compression)&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Let’s continue our original example by discussing the write functionality.&lt;/p&gt;

&lt;h3 id="writing-data"&gt;Writing data&lt;/h3&gt;

&lt;p&gt;So now that we established our client, in this section we look at the different methods you can use to write data to InfluxDB 3.0. Most will be familiar to you as they follow the same ingestion method as V2.&lt;/p&gt;

&lt;p&gt;Let’s start off with basic point building:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-python"&gt;# Continued from the Client's example

now = datetime.datetime.now(datetime.timezone.utc)

data = Point("caught").tag("trainer", "ash").tag("id", "0006").tag("num", "1")\
                                             .field("caught", "charizard")\
                                             .field("level", 10).field("attack", 30)\
                                             .field("defense", 40).field("hp", 200)\
                                             .field("speed", 10)\
                                             .field("type1", "fire").field("type2", "flying")\
                                             .time(now)

try:
    client.write(data)
except Exception as e:
    print(f"Error writing point: {e}")&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this example, you can see we build our line protocol using an instance of the Point class, which then translates into line protocol:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-bash"&gt;Point,trainer=ash,id=0006,num=1 caught="charizard",level=10i,attack=30i,defense=40i,hp=200i,speed=10i,type1="fire",type2="flying" &amp;lt;timestamp&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can also format this as an array of points:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-python"&gt;data = []
# Adding first point
data.append(
    Point("caught")
    .tag("trainer", "ash")
    .tag("id", "0006")
    .tag("num", "1")
    .field("caught", "charizard")
    .field("level", 10)
    .field("attack", 30)
    .field("defense", 40)
    .field("hp", 200)
    .field("speed", 10)
    .field("type1", "fire")
    .field("type2", "flying")
    .time(now)
)

# Adding second point
data.append(
    Point("caught")
    .tag("trainer", "ash")
    .tag("id", "0007")
    .tag("num", "2")
    .field("caught", "bulbasaur")
    .field("level", 12)
    .field("attack", 31)
    .field("defense", 31)
    .field("hp", 190)
    .field("speed", 11)
    .field("type1", "grass")
    .field("type2", "poison")
    .time(now)
)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can also write via dictionary encoding and structured data methods. One of my favorite ingest methods is via Pandas DataFrame.&lt;/p&gt;

&lt;p&gt;Let’s take a look at an example utilizing this method:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-python"&gt;# Convert the list of dictionaries to a DataFrame
caught_pokemon_df = pd.DataFrame(data).set_index('timestamp')

# Print the DataFrame
print(caught_pokemon_df)

try:
    client.write(caught_pokemon_df, data_frame_measurement_name='caught',
             data_frame_tag_columns=['trainer', 'id', 'num'])
except Exception as e:
    print(f"Error writing point: {e}")&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This example creates a Pandas DataFrame of our caught Pokemon for this session. We set the index of our dataframe to the timestamp of when the Pokemon was caught and then provide the dataframe plus the following write parameters to the ‘write()’ function:&lt;/p&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;data_frame_measurement_name&lt;/td&gt;
      &lt;td&gt;The name of the measurement you wish to write your Pandas DataFrame into.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;data_frame_tag_columns&lt;/td&gt;
      &lt;td&gt;A list of strings containing the column names you wish to make tags.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;data_frame_timestamp_column&lt;/td&gt;
      &lt;td&gt;Use this parameter to set the timestamp column if your index is not set to the timestamp.&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Make sure to check out the full example &lt;a href="https://github.com/InfluxCommunity/influxdb3-python/blob/main/Examples/pokemon-trainer/pandas-write.py"&gt;here&lt;/a&gt;. You can also find a batching example &lt;a href="https://github.com/InfluxCommunity/influxdb3-python/blob/main/Examples/pokemon-trainer/basic-write.py"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h4 id="writing-data-from-a-file"&gt;Writing data from a file&lt;/h4&gt;

&lt;p&gt;A much-requested feature of the previous client library was more ways to upload and parse different file data formats. Leveraging the utilities of PyArrow, we can now support the upload of files in the following formats:&lt;/p&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;CSV&lt;/td&gt;
      &lt;td&gt;&lt;a href="https://github.com/InfluxCommunity/influxdb3-python/blob/main/Examples/file-import/csv_write.py"&gt;Example here.&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;JSON&lt;/td&gt;
      &lt;td&gt;&lt;a href="https://github.com/InfluxCommunity/influxdb3-python/blob/main/Examples/file-import/json_write.py"&gt;Example here.&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Feather&lt;/td&gt;
      &lt;td&gt;&lt;a href="https://github.com/InfluxCommunity/influxdb3-python/blob/main/Examples/file-import/feather_write.py"&gt;Example here.&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ORC&lt;/td&gt;
      &lt;td&gt;&lt;a href="https://github.com/InfluxCommunity/influxdb3-python/blob/main/Examples/file-import/orc_write.py"&gt;Example here.&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Parquet&lt;/td&gt;
      &lt;td&gt;&lt;a href="https://github.com/InfluxCommunity/influxdb3-python/blob/main/Examples/file-import/parquet_write.py"&gt;Example here.&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h3 id="querying-data"&gt;Querying data&lt;/h3&gt;

&lt;p&gt;Now that we wrote some data into InfluxDB 3.0, let’s talk about how to query it back out. 3.0 provides a fully supported Apache Arrow Flight endpoint, which allows users to query using SQL or InfluxQL.&lt;/p&gt;

&lt;p&gt;Let’s first take a look at a basic time series query in both SQL and InfluxQL;&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-python"&gt;from influxdb_client_3 import InfluxDBClient3
import pandas as pd

client = InfluxDBClient3(
    token="",
    host="eu-central-1-1.aws.cloud2.influxdata.com",
    org="6a841c0c08328fb1",
    database="pokemon-codex")

sql = '''SELECT * FROM caught WHERE trainer = 'ash' AND time &amp;gt;= now() - interval '1 hour' LIMIT 5'''
table = client.query(query=sql, language='sql', mode='all')
print(table)

influxql = '''SELECT * FROM caught WHERE trainer = 'ash' AND time  &amp;gt; now() - 1h LIMIT 5'''
table = client.query(query=influxql, language='influxql', mode='pandas')
print(table)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you can see in this example we used the same client to query both with InfluxQL and SQL. Let’s take a quick look at the query parameters to see how they shape our returned result.&lt;/p&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;query&lt;/td&gt;
      &lt;td&gt;This parameter currently accepts the string literal of your SQL or InfluxQL query. We hope to add prepared statements to this soon.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;language&lt;/td&gt;
      &lt;td&gt;This parameter accepts a string literal of either ‘sql’ or ‘influxql’&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;mode&lt;/td&gt;
      &lt;td&gt;There are currently 5 return modes:&lt;br /&gt;1. ‘all’: this returns all the data queried as a &lt;a href="https://www.influxdata.com/blog/apache-arrow-basics-coding-apache-arrow-python/#:~:text=pyarrow%20client%20library.-,The%20basics,-In%20Apache%20Arrow"&gt;PyArrow Table&lt;/a&gt;&lt;br /&gt;2. ‘pandas’: Returns all data as a Pandas DataFrame&lt;br /&gt;3. ‘chunk’: Returns a flight reader so a user can iterate through large queries in smaller sample sizes (&lt;a href="https://github.com/InfluxCommunity/influxdb3-python/blob/main/Examples/query_type.py"&gt;see example&lt;/a&gt;)&lt;br /&gt;4. ‘reader’: Attempts to convert the stream to a RecordBatchReader&lt;br /&gt;5. ‘schema’: returns the query payload schema&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id="future-hopes"&gt;Future hopes&lt;/h2&gt;

&lt;p&gt;Rome wasn’t built in a day, and there are plenty of quality-of-life improvements and new features to add. Here is a table outlining a few:&lt;/p&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Feature&lt;/td&gt;
      &lt;td&gt;Status&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Merge the Write API from the V2 Client to remove the external library dependency.&lt;/td&gt;
      &lt;td&gt;In progress&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Prepared Statements for queries&lt;/td&gt;
      &lt;td&gt;TO DO&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Arrow table writer for InfluxDB&lt;/td&gt;
      &lt;td&gt;TO DO&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Improve Polars support&lt;/td&gt;
      &lt;td&gt;TO DO&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Integrate delta sharing&lt;/td&gt;
      &lt;td&gt;TO DO&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id="try-it-out-for-yourself"&gt;Try it out for yourself&lt;/h2&gt;

&lt;p&gt;We built the foundations of what I hope will be a great community-driven client library for InfluxDB 3.0 in Python. My call to action is if you haven’t already done so, try out the library and put it through its paces. There are so many edge cases we might not be aware of and we won’t find those without community help. I am eagerly awaiting issues and feature requests.&lt;/p&gt;
</description>
      <pubDate>Wed, 26 Jul 2023 07:35:00 +0000</pubDate>
      <link>https://www.influxdata.com/blog/client-library-deep-dive-python-part-1/</link>
      <guid isPermaLink="true">https://www.influxdata.com/blog/client-library-deep-dive-python-part-1/</guid>
      <category>Developer</category>
      <category>Product</category>
      <author>Jay Clifford (InfluxData)</author>
    </item>
    <item>
      <title>The Rebirth of InfluxQL in 3.0: A Quick Start Guide to Configuration and Usage</title>
      <description>&lt;p&gt;If we turn the clocks back to September 2013, we released &lt;a href="https://docs.influxdata.com/influxdb/cloud-serverless/query-data/influxql/"&gt;InfluxQL&lt;/a&gt; alongside InfluxDB. InfluxQL is a SQL-like query language, specifically designed to query time series data. For many of our users, InfluxQL still remains the primary way they interact with InfluxDB. Based on this feedback, InfluxQL has been reborn in &lt;a href="https://www.influxdata.com/products/influxdb-overview/"&gt;InfluxDB 3.0&lt;/a&gt; alongside native support for the &lt;a href="https://www.influxdata.com/glossary/sql/"&gt;SQL&lt;/a&gt; query language.&lt;/p&gt;

&lt;p&gt;So what do I mean by reborn? Well, in case you didn’t know, we built InfluxDB 3.0 on three key open-source projects:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.influxdata.com/glossary/apache-arrow/"&gt;Apache Arrow&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.influxdata.com/glossary/apache-parquet/"&gt;Apache Parquet&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;a href="https://www.influxdata.com/glossary/apache-datafusion/"&gt;Apache DataFusion&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Apache DataFusion acts as the foundational query engine for InfluxDB 3.0, providing our native SQL support. Our engineers extended the query engine to natively support InfluxQL as well. This allows developers to leverage the full performance of &lt;a href="https://www.influxdata.com/glossary/apache-arrow-flight-sql/"&gt;Apache Arrow Flight&lt;/a&gt; while using InfluxQL-based queries.&lt;/p&gt;

&lt;p&gt;In this blog, we will look at how you can take advantage of InfluxQL via our new v3 client libraries. We will discuss how to configure the v1 InfluxQL API for Serverless and Dedicated, which provides backward compatibility for InfluxQL plugins, such as &lt;a href="https://www.influxdata.com/grafana/"&gt;Grafana&lt;/a&gt; and &lt;a href="https://www.influxdata.com/blog/iot-easy-node-red-influxdb/"&gt;NodeRed&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="v3-client-libraries"&gt;v3 Client Libraries&lt;/h2&gt;

&lt;p&gt;We currently have five v3 community-based client libraries:&lt;/p&gt;
&lt;div class="table-container is-v-centered"&gt;
  &lt;table class="table is-bordered"&gt;
&lt;thead&gt;
&lt;tr class="has-text-centered"&gt;
&lt;th&gt;Client Library&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;th&gt;Query Languages&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/InfluxCommunity/influxdb3-csharp" target="_blank"&gt;C#&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Ready&lt;/td&gt;
&lt;td&gt;SQL, InfluxQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/InfluxCommunity/influxdb3-go" target="_blank"&gt;Go&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Ready&lt;/td&gt;
&lt;td&gt;SQL, InfluxQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/InfluxCommunity/influxdb3-python" target="_blank"&gt;Python&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Ready&lt;/td&gt;
&lt;td&gt;SQL, InfluxQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/InfluxCommunity/influxdb3-java" target="_blank"&gt;Java&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Ready&lt;/td&gt;
&lt;td&gt;SQL, InfluxQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/InfluxCommunity/influxdb3-js" target="_blank"&gt;JavaScript&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Ready&lt;/td&gt;
&lt;td&gt;SQL, InfluxQL&lt;/td&gt;
&lt;/tr&gt;  
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;Each of these client libraries support writing and querying with InfluxDB. I highly recommend checking out this &lt;a href="https://www.influxdata.com/blog/querying-writing-influxdb-cloud-status-client-libraries/"&gt;blog&lt;/a&gt; if you would like to deep dive into their current status.&lt;/p&gt;

&lt;p&gt;Let’s take a look at a few client examples utilizing the new InfluxQL query feature.&lt;/p&gt;

&lt;h3 id="python"&gt;Python&lt;/h3&gt;

&lt;p&gt;Let’s start off with a Python example:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-python"&gt;import influxdb_client_3 as InfluxDBClient3

client = InfluxDBClient3.InfluxDBClient3(
    token="&amp;lt;INSERT TOKEN&amp;gt;",
    host="eu-central-1-1.aws.cloud2.influxdata.com",
    org="6a841c0c08328fb1",
    database="database")

table = client.query(
    query="SELECT * FROM &amp;lt;MEASUREMENT&amp;gt; WHERE time &amp;gt; now() - 4h",
    language="influxql")

print(table.to_pandas())&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you can see, we create a new client instance called ‘client’. We then call &lt;code class="language-go"&gt;query()&lt;/code&gt; which takes the following parameters;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Query: String literal representation of the query you would like to perform. This can be SQL- or InfluxQL-based.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Language: This parameter indicates whether your query string literal is InfluxQL or SQL.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; It is important to set our language parameter to &lt;code class="language-go"&gt;influxql&lt;/code&gt; because SQL is the default query language.&lt;/p&gt;

&lt;h3 id="go"&gt;Go&lt;/h3&gt;

&lt;p&gt;Next, we look at a Go example:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-go"&gt;import (
  "context"
  "encoding/json"
  "fmt"
  "os"
  "github.com/InfluxCommunity/influxdb3-go/influx"
)

url := os.Getenv("INFLUXDB_URL")
token := os.Getenv("INFLUXDB_TOKEN")
database := os.Getenv("INFLUXDB_DATABASE")

// Create a new client using an InfluxDB server base URL and an authentication token
client, err := influx.New(influx.Configs{
    HostURL: url,
    AuthToken: token,
})
// Close client at the end and escalate error if present
defer func (client *influx.Client)  {
    err := client.Close()
    if err != nil {
        panic(err)
    }
}(client)

query := `SELECT * FROM &amp;lt;MEASUREMENT&amp;gt; WHERE time &amp;gt; now() - 4h`;

iterator, err := client.QueryInfluxQL(context.Background(), database, query, nil)

if err != nil {
    panic(err)
}

for iterator.Next() {
    value := iterator.Value()

    fmt.Printf("avg is %f\n", value["avg"])
    fmt.Printf("max is %f\n", value["max"])
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this example, we follow a similar practice to the Python client library except instead of using a language parameter we use the &lt;code class="language-go"&gt;client.QueryInfluxQL&lt;/code&gt; function.&lt;/p&gt;

&lt;h3 id="javascript"&gt;JavaScript&lt;/h3&gt;

&lt;p&gt;Finally, let’s consider a JavaScript example:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-javascript"&gt;import {InfluxDBClient, Point} from '../index' // replace with @influxdata/influxdb3-client in your project

type Defined&amp;lt;T&amp;gt; = Exclude&amp;lt;T, undefined&amp;gt;

/* allows to throw error as expression */
const throwReturn = &amp;lt;T&amp;gt;(err: Error): Defined&amp;lt;T&amp;gt; =&amp;gt; {
  throw err
}

async function main() {
  // Use environment variables to initialize client
  const url = 'INFLUXDB_URL'
  const token = 'INFLUXDB_TOKEN'
  const database = 'INFLUXDB_DATABASE'

  // Create a new client using an InfluxDB server base URL and an authentication token
  const client = new InfluxDBClient({url, token})

   // Prepare flightsql query
    const query = `SELECT * FROM &amp;lt;MEASUREMENT&amp;gt; WHERE time &amp;gt; now() - 4h`
    // Execute query
    const queryResult = await client.query(database, query, ‘influxql’)

    for await (const row of queryResult) {
      console.log(`avg is ${row.get('avg')}`)
      console.log(`max is ${row.get('max')}`)
    }
  } catch (err) {
    console.error(err)
  } finally {
    await client.close()
  }
}

main()&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Like the Python library, we provide credentials to instantiate the client. We call &lt;code class="language-javascript"&gt;client.query()&lt;/code&gt;, including &lt;code class="language-javascript"&gt;influxql&lt;/code&gt; as the &lt;code class="language-javascript"&gt;queryType&lt;/code&gt; parameter.&lt;/p&gt;

&lt;h2 id="v1-influxql-api"&gt;v1 InfluxQL API&lt;/h2&gt;

&lt;p&gt;We covered the client libraries, which make use of Arrow Flight to communicate with InfluxDB 3.0. This works great for building new applications but doesn’t provide a universal communication method for current InfluxQL applications and plugins because they operate using the InfluxDB API. This is where the v1 API comes into play.&lt;/p&gt;

&lt;p&gt;The v1 API has a &lt;a href="https://docs.influxdata.com/influxdb/cloud-serverless/reference/influxql/"&gt;v1 query endpoint&lt;/a&gt;, which takes the incoming query request, passes it to the query scheduler, and then runs the query. From there the result is passed back to the v1 API endpoint and then returned to complete the API request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note: As of writing this blog there is currently a distinct difference in how the V1 API is set up between Serverless and Dedicated.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;InfluxDB Cloud Dedicated&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Each database created is inherently compatible with the v1 API due to the v1 API bridge.&lt;/p&gt;

&lt;p&gt;&lt;img style="padding: 20px 0px;" src="//images.ctfassets.net/o7xu9whrs0u9/2cSoG84cmy8vx2aftfbWP7/176919f63f9814106dea34b4ec101b37/InfluxDB_Cloud_Dedicated.png" height="auto" width="600" alt="InfluxDB Cloud Dedicated" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;InfluxDB Cloud Serverless&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Serverless currently requires the creation of DBRP mappings to initialize the execution of v1 API InfluxQL queries against InfluxDB 3.0 databases.&lt;/p&gt;

&lt;p&gt;&lt;img style="padding: 20px 0px;" src="//images.ctfassets.net/o7xu9whrs0u9/12W8n6yBQKJ70n1KMjURQF/539cd633dd5256ba60754ca8df7c4d41/InfluxDB-cloud-serverless.png" height="auto" width="600" alt="InfluxDB Cloud Serverless" /&gt;&lt;/p&gt;

&lt;p&gt;Next, let’s take a look at how to configure the DBRP mappings for Serverless.&lt;/p&gt;

&lt;h3 id="configure-the-bridge-with-dbrp-serverless"&gt;Configure the bridge with DBRP (Serverless)&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Note: Always check the &lt;a href="https://docs.influxdata.com/influxdb/cloud-serverless/query-data/influxql/dbrp/"&gt;documentation&lt;/a&gt; for updates because this feature is in active development. &lt;strong&gt;Cloud Dedicated users can skip this step!&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Currently, you must manually create DBRPs for each of the databases you wish to use via the v1 API Bridge. There are two ways you can do this:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;b&gt;InfluxDB CLI:&lt;/b&gt; With this method, you must have the &lt;a href="https://docs.influxdata.com/influxdb/cloud/tools/influx-cli/"&gt;InfluxDB CLI&lt;/a&gt; installed on your host computer. Make sure that you also configure an &lt;a href="https://docs.influxdata.com/influxdb/cloud/tools/influx-cli/#provide-required-authentication-credentials"&gt;initial configuration profile&lt;/a&gt;, which points to your InfluxDB 3.0 instance. Next run the following command:

&lt;pre&gt;&lt;code class="language-bash"&gt;influx v1 dbrp create \
  --token API_TOKEN \
  --db DATABASE_NAME \
  --rp RETENTION_POLICY_NAME \
  --bucket-id BUCKET_ID \
  --default&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

     &lt;ul&gt;
       &lt;li&gt;&lt;b&gt;API token&lt;/b&gt; to authenticate. We recommend setting your token to your active InfluxDB connection configuration in the &lt;a href="https://docs.influxdata.com/influxdb/cloud-serverless/reference/cli/influx/"&gt;influx CLI&lt;/a&gt;, so you don’t have to add these parameters to each command. To set up your active InfluxDB configuration, see &lt;a href="https://docs.influxdata.com/influxdb/cloud-serverless/reference/cli/influx/config/set/"&gt;influx config set.&lt;/a&gt;&lt;/li&gt;

  &lt;li&gt;&lt;b&gt;database name&lt;/b&gt; to map&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;retention policy name&lt;/b&gt; to map&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Bucket ID&lt;/b&gt; to map to&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Default&lt;/b&gt; — this flag sets the provided retention policy as the default retention policy for the database.&lt;/li&gt;
 &lt;/ul&gt;

&lt;li&gt;&lt;b&gt;InfluxDB API:&lt;/b&gt; If you wish to interact with the API directly, you can do this via the following curl request:  

&lt;pre&gt;&lt;code class="language-bash"&gt;curl --request POST https://us-west-2-1.aws.cloud2.influxdata.com/api/v2/dbrps \
  --header "Authorization: Token API_TOKEN" \
  --header 'Content-type: application/json' \
  --data '{
        "bucketID": "BUCKET_ID",
        "database": "DATABASE_NAME",
        "default": true,
        "orgID": "ORG_ID",
        	   "retention_policy": "RETENTION_POLICY_NAME"
     		 }'&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As you can see, curl requires the same parameters as the CLI. If you have a lot of databases you want to map in Serverless then I highly recommend setting up the InfluxDB CLI and utilizing this bash script:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-bash"&gt;#!/bin/bash

# Run influx bucket list and parse the output
influx bucket list | awk '
BEGIN {
    # Skip the header line
    getline
}
{
    # Extract the values
    bucket_id = $1
    database_name = $2

    # Construct and run the influx v1 dbrp create command
    cmd = "influx v1 dbrp create --db " database_name " --rp " database_name " --bucket-id " bucket_id " --default"
    system(cmd)
}'&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will map each database/bucket to its own DBRP.&lt;/p&gt;

&lt;h3 id="grafana-influxql-datasource"&gt;Grafana InfluxQL datasource&lt;/h3&gt;

&lt;p&gt;Now that we created our first v1 mapping, let’s utilize it with the InfluxQL datasource in Grafana. Let’s take a look at the configuration in two stages:&lt;/p&gt;

&lt;h4 id="stage-1-authentication"&gt;Stage 1: Authentication&lt;/h4&gt;

&lt;p&gt;At this stage of the plugin configuration, we must modify three parameters (this excludes creating a &lt;strong&gt;Name&lt;/strong&gt; and specifying InfluxQL as your &lt;strong&gt;Query Language&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;&lt;img style="padding: 20px 0px;" src="//images.ctfassets.net/o7xu9whrs0u9/2hLhxLZaNcTzdiHYXz4SlN/f1521bce089d601cbfd669f2bee8cf05/Authentication.png" height="auto" width="600" alt="Authentication" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;URL:&lt;/strong&gt; Make sure to add your protocol and domain to this form. An example would look like:  &lt;a href="https://eu-central-1-1.aws.cloud2.influxdata.com"&gt;https://eu-central-1-1.aws.cloud2.influxdata.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Basic auth:&lt;/strong&gt; Toggle this to true.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;User/Password:&lt;/strong&gt; The username can be any string; it is not used for authentication purposes but cannot be empty. Password must be an InfluxDB API token that has enough privileges to query from the database you are going to use.&lt;/p&gt;

&lt;h4 id="stage-2-database-details"&gt;Stage 2: Database details&lt;/h4&gt;

&lt;p&gt;In this final stage, you only have one parameter to change. Note that the configuration doesn’t use the username and password parameters.&lt;/p&gt;

&lt;p&gt;&lt;img style="padding: 20px 0px;" src="//images.ctfassets.net/o7xu9whrs0u9/4QpP7FsQv1f5fpuja7igVp/d37a1b38e5c56939f5c3cedaa44472c8/Database_details.png" height="auto" width="600" alt="Database details" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Database:&lt;/strong&gt; Specify the name of the database you wish to query from.&lt;/p&gt;

&lt;h3 id="node-red-plugin"&gt;Node-RED Plugin&lt;/h3&gt;

&lt;p&gt;Let’s take a look at one more example — the &lt;a href="https://flows.nodered.org/node/node-red-contrib-influxdb"&gt;node-red-contrib-influxdb&lt;/a&gt; plugin for Node-RED. This contribution from one of our community members makes InfluxDB accessible for both querying and writing within Node-Red. Using the v1 API, we can make use of this plugin once again. Let’s split the setup into two stages:&lt;/p&gt;

&lt;h4 id="stage-1-authentication-1"&gt;Stage 1: Authentication&lt;/h4&gt;

&lt;p&gt;Like with the Grafana data source, we need to configure our connection and authentication to the v1 bridge first. To do this, we have a few parameters to configure:&lt;/p&gt;

&lt;p&gt;&lt;img style="padding: 20px 0px;" src="//images.ctfassets.net/o7xu9whrs0u9/41xYHTmPgDAsJ9KINHGkm6/0f202129e36cbff34c51936bcefd0b72/stage-1-Authentication.png" height="auto" width="600" alt="stage-1-Authentication" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Version:&lt;/strong&gt; Make sure this is set to 1.X&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Host &amp;amp; Port:&lt;/strong&gt; Strip your domain URL of any protocol (https://) and specify port ‘443’.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Database:&lt;/strong&gt; Name of the database to query from.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;User/Password:&lt;/strong&gt; The username can be given any string; it is not used for authentication purposes but cannot be empty. Password must be an InfluxDB API token that has enough privileges to query from the database you are going to use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enable Secure:&lt;/strong&gt; Make sure to enable SSL/TLS&lt;/p&gt;

&lt;h4 id="stage-2-query-details"&gt;Stage 2: Query details&lt;/h4&gt;

&lt;p&gt;Now you may form your query in Node-RED. There are only two parameters to note:&lt;/p&gt;

&lt;p&gt;&lt;img style="padding: 20px 0px;" src="//images.ctfassets.net/o7xu9whrs0u9/iw6xeTNC2pu8O36h403R0/c1ab26c2c8d6a60bcb64da8e505b5950/Stage-2_Query_details.png" height="auto" width="600" alt="Stage-2 Query details" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time Precision:&lt;/strong&gt; Make sure to set this parameter appropriately based on the timestamp stored.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Query:&lt;/strong&gt; Provide your InfluxQL query.&lt;/p&gt;

&lt;h2 id="key-takeaways"&gt;Key takeaways&lt;/h2&gt;

&lt;p&gt;InfluxQL is back and better than ever. When using the v3 client libraries, InfluxQL power users can continue utilizing the language while reaping the performance gains of InfluxDB 3.0 and the vectorized, columnar DataFusion query engine. The v1 API also provides a much-needed stepping stone to backward compatibility for well-used ecosystem products, such as Grafana and Node-RED.&lt;/p&gt;

&lt;p&gt;Now for some hard truths — InfluxQL is still under active development, so there isn’t yet a like-for-like feature representation for v1 InfluxQL. My advice is to check out the &lt;a href="https://docs.influxdata.com/influxdb/cloud-serverless/reference/influxql/"&gt;InfluxQL reference documentation&lt;/a&gt; and see what is &lt;a href="https://docs.influxdata.com/influxdb/cloud-serverless/reference/influxql/feature-support/"&gt;currently possible&lt;/a&gt;. At present, it supports most core querying functions or will support them soon. My call to action is to start pointing your InfluxQL applications at InfluxDB 3.0 and tell us about your experience in our community. In later blogs, we will deep-dive into some of the core InfluxQL functions.&lt;/p&gt;
</description>
      <pubDate>Fri, 30 Jun 2023 07:35:00 +0000</pubDate>
      <link>https://www.influxdata.com/blog/rebirth-influxql-3-0-quick-start-guide/</link>
      <guid isPermaLink="true">https://www.influxdata.com/blog/rebirth-influxql-3-0-quick-start-guide/</guid>
      <category>Product</category>
      <author>Jay Clifford (InfluxData)</author>
    </item>
  </channel>
</rss>
