Skip to content
This repository was archived by the owner on Feb 16, 2020. It is now read-only.

Commit f8fe5d2

Browse files
committed
#3 #6: Restructure. Adds deprecation for source_currency
1 parent d1da163 commit f8fe5d2

File tree

13 files changed

+153
-96
lines changed

13 files changed

+153
-96
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
__pycache__
2+
.local

Dockerfile

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@ FROM alpine:latest
22
LABEL maintainer="docker@ix.ai" \
33
ai.ix.repository="ix.ai/etherscan-exporter"
44

5-
WORKDIR /app
6-
7-
COPY src/ /app
5+
COPY etherscan-exporter/requirements.txt /etherscan-exporter/requirements.txt
86

97
RUN apk --no-cache upgrade && \
108
apk --no-cache add python3 py3-pip py3-requests py3-prometheus-client && \
11-
pip3 install --no-cache-dir -r requirements.txt
9+
pip3 install --no-cache-dir -r /etherscan-exporter/requirements.txt
10+
11+
COPY etherscan-exporter/ /etherscan-exporter/
12+
COPY etherscan-exporter.sh /usr/local/bin/etherscan-exporter.sh
1213

1314
EXPOSE 9308
1415

15-
ENTRYPOINT ["python3", "/app/etherscan-exporter.py"]
16+
ENTRYPOINT ["/usr/local/bin/etherscan-exporter.sh"]

build.sh

100644100755
File mode changed.

etherscan-exporter.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/usr/bin/env sh
2+
3+
exec python3 -m "etherscan-exporter.etherscan-exporter" "$@"

etherscan-exporter/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
""" initializes etherscan-exporter """
4+
5+
import os
6+
from .lib import log as logging
7+
8+
log = logging.setup_logger(
9+
name=__package__,
10+
level=os.environ.get('LOGLEVEL', 'INFO'),
11+
gelf_host=os.environ.get('GELF_HOST'),
12+
gelf_port=int(os.environ.get('GELF_PORT', 12201)),
13+
_ix_id=__package__,
14+
)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/usr/bin/env python3
2+
"""Prometheus Exporter for Etherscan"""
3+
4+
import logging
5+
import time
6+
import os
7+
from prometheus_client import start_http_server
8+
from prometheus_client.core import REGISTRY
9+
from .lib import constants
10+
from .etherscan_collector import EtherscanCollector
11+
from .etherscan import Etherscan
12+
13+
14+
log = logging.getLogger(__package__)
15+
version = f'{constants.VERSION}-{constants.BUILD}'
16+
17+
18+
if __name__ == '__main__':
19+
port = int(os.environ.get('PORT', 9308))
20+
log.warning(f'Starting {__package__} {version} on port {port}')
21+
log.warning("The label 'source_currency' is deprecated and will likely be removed soon")
22+
23+
etherscan = Etherscan()
24+
REGISTRY.register(EtherscanCollector(etherscan))
25+
start_http_server(port)
26+
while True:
27+
time.sleep(1)

src/etherscan-exporter.py renamed to etherscan-exporter/etherscan.py

Lines changed: 12 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -4,44 +4,13 @@
44
import logging
55
import time
66
import os
7-
import sys
87
import json
98
import requests
10-
import pygelf
11-
from prometheus_client import start_http_server
12-
from prometheus_client.core import REGISTRY, GaugeMetricFamily
13-
from .lib import constants
149

15-
LOG = logging.getLogger(__name__)
16-
logging.basicConfig(
17-
stream=sys.stdout,
18-
level=os.environ.get("LOGLEVEL", "INFO"),
19-
format='%(asctime)s.%(msecs)03d %(levelname)s {%(module)s} [%(funcName)s] %(message)s',
20-
datefmt='%Y-%m-%d %H:%M:%S'
21-
)
10+
log = logging.getLogger(__package__)
2211

23-
FILENAME = os.path.splitext(sys.modules['__main__'].__file__)[0]
24-
version = f'{constants.VERSION}-{constants.BUILD}'
2512

26-
27-
def configure_logging():
28-
""" Configures the logging """
29-
gelf_enabled = False
30-
31-
if os.environ.get('GELF_HOST'):
32-
GELF = pygelf.GelfUdpHandler(
33-
host=os.environ.get('GELF_HOST'),
34-
port=int(os.environ.get('GELF_PORT', 12201)),
35-
debug=True,
36-
include_extra_fields=True,
37-
_ix_id=FILENAME
38-
)
39-
LOG.addHandler(GELF)
40-
gelf_enabled = True
41-
LOG.info(f'Initialized logging with GELF enabled: {gelf_enabled}')
42-
43-
44-
class EtherscanCollector:
13+
class Etherscan:
4514
""" The EtherscanCollector class """
4615

4716
accounts = {}
@@ -62,10 +31,10 @@ def __init__(self):
6231

6332
def get_tokens(self):
6433
""" Gets the tokens from an account """
65-
66-
time.sleep(1) # Ensure that we don't get rate limited
34+
log.info('Retrieving the tokens')
6735
for account in self.accounts:
6836
for token in self.settings['tokens']:
37+
log.debug(f"Retrieving the balance for {token['short']} on the account {account}")
6938
request_data = {
7039
'module': 'account',
7140
'action': 'tokenbalance',
@@ -77,14 +46,13 @@ def get_tokens(self):
7746
decimals = 18
7847
if token.get('decimals', -1) >= 0:
7948
decimals = int(token['decimals'])
80-
LOG.debug(f"{decimals} decimals for {token['short']}")
8149
try:
8250
req = requests.get(self.settings['url'], params=request_data).json()
8351
except (
8452
requests.exceptions.ConnectionError,
8553
requests.exceptions.ReadTimeout,
8654
) as error:
87-
LOG.exception(f'Exception caught: {error}')
55+
log.exception(f'Exception caught: {error}')
8856
req = {}
8957
if req.get('result') and int(req['result']) > 0:
9058
self.tokens.update({
@@ -96,79 +64,32 @@ def get_tokens(self):
9664
'value': int(req['result']) / (10**decimals) if decimals > 0 else int(req['result'])
9765
}
9866
})
99-
100-
LOG.debug(f'Tokens: {self.tokens}')
67+
time.sleep(1) # Ensure that we don't get rate limited
68+
log.debug(f'Tokens: {self.tokens}')
69+
return self.tokens
10170

10271
def get_balances(self):
10372
""" Gets the current balance for an account """
73+
log.info('Retrieving the account balances')
10474
request_data = {
10575
'module': 'account',
10676
'action': 'balancemulti',
10777
'address': self.settings['addresses'],
10878
'tag': 'latest',
10979
'apikey': self.settings['api_key'],
11080
}
111-
LOG.debug(f'Request data: {request_data}')
11281
try:
11382
req = requests.get(self.settings['url'], params=request_data).json()
11483
except (
11584
requests.exceptions.ConnectionError,
11685
requests.exceptions.ReadTimeout,
11786
) as error:
118-
LOG.exception(f'Exception caught: {error}')
87+
log.exception(f'Exception caught: {error}')
11988
req = {}
12089
if req.get('message') == 'OK' and req.get('result'):
12190
for result in req.get('result'):
12291
self.accounts.update({
12392
result['account']: float(result['balance'])/(1000000000000000000)
12493
})
125-
LOG.debug(f'Accounts: {self.accounts}')
126-
127-
def describe(self):
128-
""" Just a needed method, so that collect() isn't called at startup """
129-
return []
130-
131-
def collect(self):
132-
"""The method that actually does the collecting"""
133-
metrics = {
134-
'account_balance': GaugeMetricFamily(
135-
'account_balance',
136-
'Account Balance',
137-
labels=['source_currency', 'currency', 'account', 'type']
138-
),
139-
}
140-
self.get_balances()
141-
for account in self.accounts:
142-
metrics['account_balance'].add_metric(
143-
value=(self.accounts[account]),
144-
labels=[
145-
'ETH',
146-
'ETH',
147-
account,
148-
'etherscan'
149-
]
150-
)
151-
152-
self.get_tokens()
153-
for token in self.tokens:
154-
metrics['account_balance'].add_metric(
155-
value=(self.tokens[token]['value']),
156-
labels=[
157-
self.tokens[token]['name_short'],
158-
self.tokens[token]['name_short'],
159-
self.tokens[token]['account'],
160-
'etherscan'
161-
]
162-
)
163-
for metric in metrics.values():
164-
yield metric
165-
166-
167-
if __name__ == '__main__':
168-
configure_logging()
169-
port = int(os.environ.get('PORT', 9308))
170-
LOG.info(f'Starting {__package__} {version} on port {port}')
171-
REGISTRY.register(EtherscanCollector())
172-
start_http_server(port)
173-
while True:
174-
time.sleep(1)
94+
log.debug(f'Accounts: {self.accounts}')
95+
return self.accounts
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#!/usr/bin/env python3
2+
"""Prometheus Exporter for Etherscan"""
3+
4+
import logging
5+
from prometheus_client.core import GaugeMetricFamily
6+
7+
log = logging.getLogger(__package__)
8+
9+
10+
class EtherscanCollector:
11+
""" The EtherscanCollector class """
12+
13+
accounts = {}
14+
tokens = {}
15+
16+
def __init__(self, etherscan):
17+
self.etherscan = etherscan
18+
19+
def describe(self):
20+
""" Just a needed method, so that collect() isn't called at startup """
21+
return []
22+
23+
def collect(self):
24+
"""The method that actually does the collecting"""
25+
metrics = {
26+
'account_balance': GaugeMetricFamily(
27+
'account_balance',
28+
'Account Balance',
29+
labels=['source_currency', 'currency', 'account', 'type']
30+
),
31+
}
32+
accounts = self.etherscan.get_balances()
33+
for account in accounts:
34+
metrics['account_balance'].add_metric(
35+
value=(accounts[account]),
36+
labels=[
37+
'ETH',
38+
'ETH',
39+
account,
40+
'etherscan'
41+
]
42+
)
43+
44+
tokens = self.etherscan.get_tokens()
45+
for token in tokens:
46+
metrics['account_balance'].add_metric(
47+
value=(tokens[token]['value']),
48+
labels=[
49+
tokens[token]['name_short'],
50+
tokens[token]['name_short'],
51+
tokens[token]['account'],
52+
'etherscan'
53+
]
54+
)
55+
for metric in metrics.values():
56+
yield metric
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)