Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
ramilexe committed Dec 4, 2020
0 parents commit c3eb8ac
Show file tree
Hide file tree
Showing 10 changed files with 739 additions and 0 deletions.
11 changes: 11 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
SERVER_PORT=3000
SERVER_HOST=127.0.0.1

ETHERSCAN_API_KEY=

# DB Statediff
STATEDIFF_PG_HOST=
STATEDIFF_PG_PORT=
STATEDIFF_PG_USER=
STATEDIFF_PG_PASSWORD=
STATEDIFF_PG_DATABASE=
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
.env
20 changes: 20 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM node:10.15.2-alpine

# Create app directory
WORKDIR /app

RUN apk add --no-cache \
make g++ git ca-certificates

#RUN npm config set unsafe-perm true && npm install -g typescript ts-node

COPY package*.json ./

RUN yarn

COPY . .

#RUN npm run build

EXPOSE 3000

15 changes: 15 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "eth-state-metrics",
"version": "1.0.0",
"description": "NodeJS Service to pull last block from etherscan and DB and provide Prometheus metrics",
"main": "index.js",
"license": "MIT",
"private": true,
"dependencies": {
"axios": "^0.21.0",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"pg": "^8.5.1",
"prom-client": "^12.0.0"
}
}
42 changes: 42 additions & 0 deletions src/db.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const { Client } = require('pg');

class DB {
constructor(type, user, password, database, host, port) {
this.type = type;
this.client = new Client({
user,
host,
database,
password,
port,
});

this.connecting = false;
}

async getBlockNumber() {
if (!this.connecting) {
await this.connect();
this.connecting = true;
}

return this.client.query('SELECT block_number FROM eth.header_cids ORDER BY block_number DESC LIMIT 1')
.then((res) => {
if (res.rows.length) {
return {
type: this.type,
blockNumber: parseInt(res.rows[0].block_number, 10),
}
}

return null;
});

}

connect() {
return this.client.connect();
}
}

module.exports = DB;
12 changes: 12 additions & 0 deletions src/error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

class AppError extends Error {
constructor(type, message) {
super(`Error ${type}: ${message}`);
this.data = {
type,
message,
}
}
}

module.exports = AppError;
27 changes: 27 additions & 0 deletions src/etherscan.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const axios = require('axios');
const AppError = require('./error');

const etherscanClient = axios.create({
baseURL: 'https://api.etherscan.io',
});


const getBlockNumber = () => {
return etherscanClient.get(`/api?module=proxy&action=eth_blockNumber&apikey=${process.env.ETHERSCAN_API_KEY}`)
.then((response) => {
const data = response.data;

// console.log(data);

if (data.status === '0') {
throw new AppError('etherscan', data.result);
}

return {
type: 'etherscan',
blockNumber: parseInt(data.result, 16),
}
})
}

module.exports = {getBlockNumber};
72 changes: 72 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
require('dotenv').config()
const express = require('express')
const etherscan = require('./etherscan');
const AppError = require('./error');
const prom = require('./prometheus');
const DB = require('./db');

const startServer = () => {
const server = express();

server.get('/metrics', async (req, res) => {
try {
res.set('Content-Type', prom.register.contentType)
res.end(await prom.register.metrics())
} catch (ex) {
res.status(500).end(ex)
}
});

server.listen(process.env.SERVER_PORT);
}

const main = async () => {
startServer();

const statediffUser = process.env.STATEDIFF_PG_USER;
const statediffPassword = process.env.STATEDIFF_PG_PASSWORD;
const statediffDB = process.env.STATEDIFF_PG_DATABASE;
const statediffHost = process.env.STATEDIFF_PG_HOST;
const statediffPort = process.env.STATEDIFF_PG_PORT;

const dbStateDiff = new DB('statediff', statediffUser, statediffPassword, statediffDB, statediffHost, statediffPort)
const dbStateDiffBlockNumber = dbStateDiff.getBlockNumber();

// Etherscan
const etherscanBlock = etherscan.getBlockNumber();

const results = await Promise.allSettled([
etherscanBlock,
dbStateDiffBlockNumber,

])
// console.log(results);

for (const result of results) {
// console.log(result);

if (result.status === 'rejected') {
if (result.reason instanceof AppError) {
const errorData = result.reason.data;
console.log(errorData.type, errorData.message);
} else {
console.error(result.reason);
}
} else if (result.status === 'fulfilled') {
const value = result.value;
switch (value.type) {
case 'etherscan':
prom.etherscanGauge.set(value.blockNumber);

break;
case 'statediff':
prom.statediffDBGauge.set(value.blockNumber);

break;
}
}
}
}

main().catch((e) => console.error(e));

13 changes: 13 additions & 0 deletions src/prometheus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const client = require('prom-client');

const collectDefaultMetrics = client.collectDefaultMetrics;
const Registry = client.Registry;
const register = new Registry();
const prefix = 'eth_state_metrics_';
collectDefaultMetrics({ register });

const etherscanGauge = new client.Gauge({ name: `${prefix}etherscan`, help: 'Etherscan Block Number', registers: [register]});
const statediffDBGauge = new client.Gauge({ name: `${prefix}statediff_db`, help: 'Statediff DB Block Number', registers: [register]});

module.exports = {etherscanGauge, statediffDBGauge, register};

Loading

0 comments on commit c3eb8ac

Please sign in to comment.