Blockchain monitoring tool that tracks block heights, timestamps, and delays across multiple blockchain networks.
- Multi-chain support (Ethereum, Cosmos ecosystem, Sui, and more)
- Prometheus metrics export
- Dynamic chain addition via YAML configuration
- Graceful shutdown and config reload (SIGHUP)
- Docker support
# Build
cd cogwatch
make build
# Run
./cogwatch config.yaml# Build image
make docker-build
# Run container
make docker-run
# Reload config without restart
make docker-reloadEdit cogwatch/config.yaml:
check_interval: 30 # Check endpoints every 30 seconds
request_timeout: 10 # HTTP request timeout in seconds
shutdown_timeout: 5 # Graceful shutdown timeout in seconds
metrics:
port: 9090
path: /metrics
groups:
- name: "mainnet-ethereum"
chain_type: "ethereum_execution"
endpoints:
- "http://eth-node1.example.com:8545"
- "http://eth-node2.example.com:8545"TIMECOG_CHAIN_MAPPINGS: Path to chain_mappings.yaml file (default:chain_mappings.yamlin current directory)
# Use custom path
export TIMECOG_CHAIN_MAPPINGS=/etc/cogwatch/chain_mappings.yaml
./cogwatch config.yaml
# Use default (chain_mappings.yaml in current directory)
./cogwatch config.yamlEdit timecog/chain_mappings.yaml:
formats:
ethereum_execution:
chains:
- ethereum
- base
- optimism
# Add your new EVM chain here
- your_chain_name
timeunit_name: block_number
# Or create a new format for non-EVM chains
your_new_format:
chains:
- your_chain_name
timeunit_name: block_height # or slot, checkpoint, etc.Only needed if creating a new format. For existing formats (like EVM chains), skip this step.
Create timecog/clients/your_chain.go:
package clients
import (
"context"
"encoding/json"
"fmt"
)
type YourChainClient struct{}
type YourChainResponse struct {
// Define your chain's JSON response structure
}
func (c *YourChainClient) Fetch(ctx context.Context, url string) ([]byte, error) {
return doHTTPRequest(ctx, "GET", url, nil)
}
func (c *YourChainClient) Parse(data []byte) (*ParseResult, error) {
var response YourChainResponse
if err := json.Unmarshal(data, &response); err != nil {
return nil, fmt.Errorf("failed to unmarshal: %w", err)
}
return &ParseResult{
Value: /* extract block height/slot/etc */,
Timestamp: /* extract timestamp */,
}, nil
}Edit timecog/manager.go, add case to switch statement:
switch format {
case "ethereum_execution":
client = &clients.EthExecutionClient{}
case "your_new_format":
client = &clients.YourChainClient{}
// ...
}Edit cogwatch/config.yaml:
groups:
- name: "mainnet-yourchain"
chain_type: "your_chain_name"
endpoints:
- "http://your-rpc-endpoint:port"# Run tests
cd timecog
go test ./...
# Build and run
cd ../cogwatch
make build
./cogwatch config.yamlThat's it! No code recompilation needed for adding chains to existing formats.
Access Prometheus metrics at http://localhost:9090/metrics:
blockchain_time_unit_value- Current block height/slot/checkpointblockchain_block_timestamp_seconds- Block timestamp in Unix secondsblockchain_scrape_errors_total- Total scrape errors by typeblockchain_failure_since- Unix timestamp of first failure in current sequence
MIT