Compare commits
10 Commits
b8d9300bca
...
19ac4dec45
Author | SHA1 | Date | |
---|---|---|---|
19ac4dec45 | |||
3a31a30fc7 | |||
55a31bdbb1 | |||
7a8a8ee260 | |||
4aa164d148 | |||
9d79cecb01 | |||
a50eec4fc4 | |||
fb765920b4 | |||
6a7d4e922b | |||
c19ecae493 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -292,6 +292,7 @@ TSWLatexianTemp*
|
||||
|
||||
.ipynb_checkpoints/
|
||||
env/
|
||||
.env
|
||||
__pycache__/
|
||||
test/
|
||||
venv/
|
||||
|
63
README.md
Normal file
63
README.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# PeerTube collector
|
||||
|
||||
peertube-collector is a project designed to collect and analyze WebRTC statistics from a Chromium browser and export them to a Prometheus PushGateway service. This project includes a Docker setup for running the necessary services.
|
||||
|
||||
## Working Project Structure
|
||||
|
||||
```
|
||||
peertube-collector/
|
||||
├── requirements.txt
|
||||
├── telegraf.conf
|
||||
├── docker-compose.yml
|
||||
├── Dockerfile
|
||||
├── main.py
|
||||
├── .env
|
||||
└── utils/
|
||||
└── webrtc-internals-exporter/
|
||||
```
|
||||
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker
|
||||
- Docker Compose
|
||||
|
||||
## Setup
|
||||
|
||||
1. Clone the repository:
|
||||
```sh
|
||||
git clone <repository-url>
|
||||
cd peertube-collector
|
||||
```
|
||||
|
||||
2. Create and configure the environment file based on the `.env.example` file:
|
||||
```sh
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
|
||||
3. Build and start the Docker containers:
|
||||
```sh
|
||||
docker-compose up --build
|
||||
```
|
||||
|
||||
## Components
|
||||
|
||||
### Docker Compose
|
||||
|
||||
The `docker-compose.yml` file defines the following services:
|
||||
- **selenium**: Runs a Selenium standalone Chromium container.
|
||||
- **telegraf**: Collects and sends metrics to the specified output.
|
||||
- **collector**: Runs the main Python application to collect WebRTC stats.
|
||||
|
||||
### Dockerfile
|
||||
|
||||
The `Dockerfile` sets up the Python environment and installs the necessary dependencies to run the `main.py` script.
|
||||
|
||||
### Main Python Script
|
||||
|
||||
The `main.py` script sets up the Selenium WebDriver, collects WebRTC stats, and sends them to the Telegraf service.
|
||||
|
||||
### WebRTC Internals Exporter
|
||||
|
||||
The `webrtc-internals-exporter` directory contains a Chromium extension that collects WebRTC stats from the browser.
|
@@ -2,8 +2,6 @@ services:
|
||||
selenium:
|
||||
container_name: selenium-standalone-chromium
|
||||
image: selenium/standalone-chromium:129.0
|
||||
ports:
|
||||
- "7900:7900"
|
||||
volumes:
|
||||
- ./webrtc-internals-exporter:/tmp/webrtc-internals-exporter:ro
|
||||
shm_size: "2g"
|
||||
@@ -13,27 +11,44 @@ services:
|
||||
interval: 5s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
networks:
|
||||
- backend
|
||||
network_mode: host
|
||||
|
||||
telegraf:
|
||||
container_name: telegraf
|
||||
image: telegraf:1.33.1
|
||||
volumes:
|
||||
- ./telegraf.conf:/etc/telegraf/telegraf.conf:ro
|
||||
environment:
|
||||
- DATABASE=${TELEGRAF_MONGODB_DATABASE:?"Database name is required"}
|
||||
- DSN=${TELEGRAF_MONGODB_DSN:?"DSN is required"}
|
||||
- HOSTNAME=${TELEGRAF_HOSTNAME:?"Hostname is required"}
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8080"]
|
||||
interval: 5s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
|
||||
collector:
|
||||
container_name: collector
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
image: gitea.kobim.cloud/kobim/peertube-collector
|
||||
#build:
|
||||
#context: .
|
||||
#dockerfile: Dockerfile
|
||||
depends_on:
|
||||
selenium:
|
||||
condition: service_healthy
|
||||
telegraf:
|
||||
condition: service_started
|
||||
condition: service_healthy
|
||||
environment:
|
||||
- VIDEO_URL=${VIDEO_URL:?"Video URL is required"}
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "9092:9092"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
networks:
|
||||
- backend
|
||||
|
||||
|
8
example.env
Normal file
8
example.env
Normal file
@@ -0,0 +1,8 @@
|
||||
# User defined hostname persisted across all sessions, used to keep track of the same user
|
||||
TELEGRAF_HOSTNAME=
|
||||
# MongoDB connection string
|
||||
TELEGRAF_MONGODB_DSN=
|
||||
# MongoDB database name to store the data
|
||||
TELEGRAF_MONGODB_DATABASE=
|
||||
# URL of the video to be analyzed
|
||||
VIDEO_URL=
|
17
main.py
17
main.py
@@ -28,7 +28,7 @@ def setupLogger():
|
||||
)
|
||||
logger.addHandler(logger_handler)
|
||||
|
||||
def interrupt_handler(signum, driver: webdriver.Chrome):
|
||||
def interrupt_handler(signum, driver: webdriver.Remote):
|
||||
logger.info(f'Handling signal {signum} ({signal.Signals(signum).name}).')
|
||||
|
||||
driver.quit()
|
||||
@@ -41,7 +41,7 @@ def setupChromeDriver():
|
||||
chrome_options.add_argument("--no-sandbox")
|
||||
chrome_options.add_argument("--mute-audio")
|
||||
chrome_options.add_argument("--window-size=1280,720")
|
||||
chrome_options.add_argument("--disable-dev-shm-usage")
|
||||
#chrome_options.add_argument("--disable-dev-shm-usage")
|
||||
chrome_options.add_argument("--no-default-browser-check")
|
||||
chrome_options.add_argument("--disable-features=WebRtcHideLocalIpsWithMdns")
|
||||
#chrome_options.add_argument(f"--load-extension={os.path.abspath(os.path.join(os.path.dirname(__file__), 'webrtc-internals-exporter'))}")
|
||||
@@ -49,7 +49,7 @@ def setupChromeDriver():
|
||||
chrome_options.add_experimental_option('prefs', {'intl.accept_languages': 'en,en_US'})
|
||||
|
||||
#driver = webdriver.Chrome(options=chrome_options)
|
||||
driver = webdriver.Remote(command_executor='http://selenium-standalone-chromium:4444', options=chrome_options)
|
||||
driver = webdriver.Remote(command_executor='http://host.docker.internal:4444', options=chrome_options)
|
||||
logger.log(logging.INFO, 'Chrome driver setup complete.')
|
||||
|
||||
return driver
|
||||
@@ -157,7 +157,7 @@ def downloadStats(driver: webdriver.Chrome, peersDict: dict):
|
||||
|
||||
saveStats([stats])
|
||||
|
||||
def setupStats(driver: webdriver.Chrome, url: str):
|
||||
def setupStats(driver: webdriver.Remote, url: str):
|
||||
logger.log(logging.INFO, 'Setting up stats.')
|
||||
actions = ActionChains(driver)
|
||||
wait = WebDriverWait(driver, 30, poll_frequency=0.2)
|
||||
@@ -183,9 +183,14 @@ if __name__ == '__main__':
|
||||
|
||||
signal.signal(signal.SIGINT, lambda signum, frame: interrupt_handler(signum, driver))
|
||||
|
||||
setupStats(driver, "https://tube.kobim.cloud/w/iN2T8PmbSb4HJTDA2rV3sg")
|
||||
url = os.getenv('VIDEO_URL')
|
||||
if url is None:
|
||||
logger.error('VIDEO_URL environment variable is not set.')
|
||||
raise SystemExit(1)
|
||||
|
||||
setupStats(driver, url)
|
||||
|
||||
logger.log(logging.INFO, 'Starting server collector.')
|
||||
httpd = HTTPServer(('collector', 9092), partial(Handler, downloadStats, driver, logger))
|
||||
httpd = HTTPServer(('', 9092), partial(Handler, downloadStats, driver, logger))
|
||||
logger.info('Server collector started.')
|
||||
httpd.serve_forever()
|
@@ -1,3 +1,8 @@
|
||||
[agent]
|
||||
flush_interval = "20s"
|
||||
hostname = "${HOSTNAME}"
|
||||
omit_hostname = false
|
||||
|
||||
[[processors.dedup]]
|
||||
dedup_interval = "600s"
|
||||
|
||||
@@ -14,20 +19,20 @@
|
||||
[inputs.socket_listener.xpath.tags]
|
||||
url = "url"
|
||||
session = "session"
|
||||
#id = ??
|
||||
#state = ??
|
||||
host = "host"
|
||||
|
||||
[inputs.socket_listener.xpath.fields]
|
||||
player = "player"
|
||||
peers = "peers"
|
||||
|
||||
[[outputs.health]]
|
||||
service_address = "http://:8080"
|
||||
|
||||
[[outputs.file]]
|
||||
files = ["stdout"]
|
||||
data_format = "json"
|
||||
|
||||
[[outputs.mongodb]]
|
||||
dsn = "mongodb://stats_user:%40z%5EVFhN7q%25vzit@192.168.86.120:27017/?authSource=statistics"
|
||||
database = "statistics"
|
||||
granularity = "seconds"
|
||||
|
||||
# docker run --rm -v .\peertube\statnerd\telegraf.conf:/etc/telegraf/telegraf.conf:ro -p 8094:8094/udp telegraf
|
||||
dsn = "${DSN}"
|
||||
database = "${DATABASE}"
|
||||
granularity = "seconds"
|
@@ -21,4 +21,9 @@ class Handler(BaseHTTPRequestHandler):
|
||||
else:
|
||||
self.send_response(404)
|
||||
self.end_headers()
|
||||
self.wfile.write(b'404 Not Found')
|
||||
self.wfile.write(b'404 Not Found')
|
||||
|
||||
def do_GET(self):
|
||||
self.send_response(404)
|
||||
self.end_headers()
|
||||
self.wfile.write(b'404 Not Found')
|
@@ -9,15 +9,13 @@ log("loaded");
|
||||
import "/assets/pako.min.js";
|
||||
|
||||
const DEFAULT_OPTIONS = {
|
||||
url: "http://collector:9092",
|
||||
url: "http://localhost:9092",
|
||||
username: "",
|
||||
password: "",
|
||||
updateInterval: 2,
|
||||
gzip: false,
|
||||
job: "webrtc-internals-exporter",
|
||||
enabledOrigins: {
|
||||
"https://tube.kobim.cloud": true,
|
||||
},
|
||||
enabledOrigins: { },
|
||||
enabledStats: ["data-channel", "local-candidate", "remote-candidate"]
|
||||
};
|
||||
|
||||
@@ -46,7 +44,7 @@ async function updateTabInfo(tab) {
|
||||
const tabId = tab.id;
|
||||
const origin = new URL(tab.url || tab.pendingUrl).origin;
|
||||
|
||||
if (options.enabledOrigins && options.enabledOrigins[origin] === true) {
|
||||
if (options.enabledOrigins) {
|
||||
const { peerConnectionsPerOrigin } = await chrome.storage.local.get(
|
||||
"peerConnectionsPerOrigin",
|
||||
);
|
||||
|
@@ -46,8 +46,7 @@ if (window.location.protocol.startsWith("http")) {
|
||||
log(`options loaded:`, ret);
|
||||
options.url = ret.url || "";
|
||||
options.enabled =
|
||||
ret.enabledOrigins &&
|
||||
ret.enabledOrigins[window.location.origin] === true;
|
||||
ret.enabledOrigins;
|
||||
options.updateInterval = (ret.updateInterval || 2) * 1000;
|
||||
options.enabledStats = Object.values(ret.enabledStats || {});
|
||||
sendOptions();
|
||||
|
@@ -65,7 +65,6 @@ class WebrtcInternalExporter {
|
||||
}
|
||||
}
|
||||
|
||||
//if (stats.length !== 0) {
|
||||
window.postMessage(
|
||||
{
|
||||
event: "webrtc-internal-exporter:peer-connections-stats",
|
||||
@@ -75,7 +74,6 @@ class WebrtcInternalExporter {
|
||||
);
|
||||
|
||||
log(`Stats collected:`, stats);
|
||||
//}
|
||||
|
||||
setTimeout(this.collectAllStats.bind(this), this.updateInterval);
|
||||
return stats;
|
||||
|
Reference in New Issue
Block a user