Test Failed
Push — develop ( 24eb6c...ad5e7f )
by Nicolas
02:52 queued 14s
created

glances.exports.glances_influxdb2.Export._normalize()   D

Complexity

Conditions 12

Size

Total Lines 58
Code Lines 32

Duplication

Lines 58
Ratio 100 %

Importance

Changes 0
Metric Value
cc 12
eloc 32
nop 4
dl 58
loc 58
rs 4.8
c 0
b 0
f 0

1 Method

Rating   Name   Duplication   Size   Complexity  
A glances.exports.glances_influxdb2.Export.export() 0 21 5

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like glances.exports.glances_influxdb2.Export._normalize() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
#
2
# This file is part of Glances.
3
#
4
# SPDX-FileCopyrightText: 2022 Nicolas Hennion <[email protected]>
5
#
6
# SPDX-License-Identifier: LGPL-3.0-only
7
#
8
9
"""InfluxDB (from to InfluxDB 1.8+ to <3.0) interface class."""
10
11
import sys
12
from platform import node
13
14
from influxdb_client import InfluxDBClient, WriteOptions
15
16
from glances.exports.export import GlancesExport
17
from glances.logger import logger
18
19
20
class Export(GlancesExport):
21
    """This class manages the InfluxDB export module."""
22
23
    def __init__(self, config=None, args=None):
24
        """Init the InfluxDB export IF."""
25
        super().__init__(config=config, args=args)
26
27
        # Mandatory configuration keys (additional to host and port)
28
        self.org = None
29
        self.bucket = None
30
        self.token = None
31
32
        # Optional configuration keys
33
        self.protocol = "http"
34
        self.prefix = None
35
        self.tags = None
36
        self.hostname = None
37
        self.interval = None
38
39
        # Load the InfluxDB configuration file
40
        self.export_enable = self.load_conf(
41
            "influxdb2",
42
            mandatories=["host", "port", "user", "password", "org", "bucket", "token"],
43
            options=["protocol", "prefix", "tags", "interval"],
44
        )
45
        if not self.export_enable:
46
            exit("Missing influxdb2 config")
47
48
        # Interval between two exports (in seconds)
49
        if self.interval is None:
50
            self.interval = 0
51
        try:
52
            self.interval = int(self.interval)
53
        except ValueError:
54
            logger.warning("InfluxDB export interval is not an integer, use default value")
55
            self.interval = 0
56
        # and should be set to the Glances refresh time if the value is 0
57
        self.interval = self.interval if self.interval > 0 else self.args.time
58
        logger.debug(f"InfluxDB export interval is set to {self.interval} seconds")
59
60
        # The hostname is always add as a tag
61
        self.hostname = node().split(".")[0]
62
63
        # Init the InfluxDB client
64
        self.client = self.init()
65
66
    def init(self):
67
        """Init the connection to the InfluxDB server."""
68
        if not self.export_enable:
69
            return None
70
71
        url = f"{self.protocol}://{self.host}:{self.port}"
72
        try:
73
            # See docs: https://influxdb-client.readthedocs.io/en/stable/api.html#influxdbclient
74
            client = InfluxDBClient(
75
                url=url,
76
                enable_gzip=False,
77
                verify_ssl=False,
78
                org=self.org,
79
                token=self.token,
80
            )
81
        except Exception as e:
82
            logger.critical(f"Cannot connect to InfluxDB server '{url}' ({e})")
83
            sys.exit(2)
84
        else:
85
            logger.info(f"Connected to InfluxDB server version {client.health().version} ({client.health().message})")
86
87
        # Create the write client
88
        return client.write_api(
89
            write_options=WriteOptions(
90
                batch_size=500,
91
                flush_interval=self.interval * 1000,
92
                jitter_interval=2000,
93
                retry_interval=5000,
94
                max_retries=5,
95
                max_retry_delay=30000,
96
                exponential_base=2,
97
            )
98
        )
99
100
    def export(self, name, columns, points):
101
        """Write the points to the InfluxDB server."""
102
        # Manage prefix
103
        if self.prefix is not None:
104
            name = self.prefix + "." + name
105
        # Write input to the InfluxDB database
106
        if not points:
107
            logger.debug(f"Cannot export empty {name} stats to InfluxDB")
108
        else:
109
            try:
110
                self.client.write(
111
                    self.bucket,
112
                    self.org,
113
                    self.normalize_for_influxdb(name, columns, points),
114
                    time_precision="s",
115
                )
116
            except Exception as e:
117
                # Log level set to warning instead of error (see: issue #1561)
118
                logger.warning(f"Cannot export {name} stats to InfluxDB ({e})")
119
            else:
120
                logger.debug(f"Export {name} stats to InfluxDB")
121