diff --git a/.gitignore b/.gitignore index 9c7dffa2c1..8996a5ded5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ *.swp .env* docker-compose.override.yml +log-analyser/grafana +**/.DS_Store +**/.idea diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b2afb2844..479db34b48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,52 @@ +## stable-9646 + +Based on stable release 9646. + +* 0dad31d fix(jicofo) enable jigasi brewery with ENABLE_TRANSCRIPTIONS +* fae66ad fix(jibri): IGNORE_CERTIFICATE_ERRORS as boolean +* 54baee2 feat(prosody): custom metrics of stanza counts for prosody service implemented (#1862) +* a88dd8b feat(jvb) default to using dcSCTP +* d2c26aa fix(jigasi) add missing variables to jigasi.yml +* 41559d6 feat(log-analyser): added grafana dashboard provisioning (#1855) +* 2e9e6ca misc: working on unstable + +## stable-9584-1 + +Based on stable release 9584-1. + +* 29a4523 feat(jvb) add JVB_CC_TRUST_BWE environment variable +* 0f7be54 feat(prometheus): Prometheus container and basic scraping configuration (#1838) +* 9c87bba feat(jitsi-meet): added grafana loki and otel integration for log analysis (#1844) +* fcb90ba fix(web): whiteboard config.js syntax error (#1851) +* 811518b misc: working on unstable + +## stable-9584 + +Based on stable release 9584. + +* b4604f3 feat(whiteboard) add builtin whiteboard integration +* 49bd165 feat(jibri) update Chrome to 126 +* 980703b fix(jibri): display modes in xorg config +* c65d2bd feat(jigasi,jicofo,jvb,jibri,prosody): add healthcheck.sh scripts and prosody http_health mod +* d2ac43d feat(jigasi): Add new environment variables for jigasi configuration (#1841) +* fbc250e feat(prosody): openmetrics module support (#1832) +* 2adac72 feat(prosody): Drop non existing config. +* e22b4f3 feat(jibri): Adds more fonts. +* 982e577 feat(jicofo,jvb,web) default to using SCTP based datachannels +* 55c975f fix(jicofo): use integer for port value to fix addition (#1826) +* 7c8763f base: update tpl to version 1.3.0 +* 1d3c0f1 jibri: fail to start if the SYS_ADMIN cap is missing (#1816) +* cacee4e jvb: adds autoscaler sidecar hook to signal final shutdown (#1809) +* 726b0f0 jibri: adds autoscaler sidecar hook to signal final shutdown (#1810) +* f2b2cc4 etherpad: update image version and settings +* 731d6d1 base: update tpl to make toBool more resilient +* 59c4eb2 jvb: add fallback WS server ID +* 9a54843 jvb: add ability to configure the TLS option for colibri WS +* 79a4635 jvb: add ability to disable XMPP +* 77ce86a jvb: add ability to enable SCTP datachannels +* 76ffaa7 jicofo, jvb: fix OCTO + SCTP behaviour +* 0298a30 misc: working on unstable + ## stable-9457-2 Based on stable release 9457-2. diff --git a/base/Dockerfile b/base/Dockerfile index 463bd21a6d..37c96a5e8b 100644 --- a/base/Dockerfile +++ b/base/Dockerfile @@ -13,8 +13,8 @@ RUN \ *) echo "unsupported architecture"; exit 1 ;; \ esac && \ apt-dpkg-wrap apt-get update && \ - apt-dpkg-wrap apt-get install -y apt-transport-https apt-utils ca-certificates gnupg wget && \ - wget -qO /usr/bin/tpl https://github.com/jitsi/tpl/releases/download/v1.1.1/tpl-linux-${TPL_ARCH} && \ + apt-dpkg-wrap apt-get install -y apt-transport-https apt-utils ca-certificates gnupg wget curl && \ + wget -qO /usr/bin/tpl https://github.com/jitsi/tpl/releases/download/v1.3.0/tpl-linux-${TPL_ARCH} && \ # Workaround S6 bug when /bin is a symlink wget -qO /tmp/s6.tar.gz https://github.com/just-containers/s6-overlay/releases/download/v1.22.1.0/s6-overlay-${S6_ARCH}.tar.gz && \ mkdir /tmp/s6 && \ diff --git a/docker-compose.yml b/docker-compose.yml index ba2f00ba12..37567d5ef8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,7 @@ version: '3.5' services: # Frontend web: - image: jitsi/web:${JITSI_IMAGE_VERSION:-stable-9457-2} + image: jitsi/web:${JITSI_IMAGE_VERSION:-stable-9646} restart: ${RESTART_POLICY:-unless-stopped} ports: - '${HTTP_PORT}:80' @@ -171,8 +171,8 @@ services: - XMPP_MUC_DOMAIN - XMPP_RECORDER_DOMAIN - XMPP_PORT - - WHITEBOARD_ENABLED - WHITEBOARD_COLLAB_SERVER_PUBLIC_URL + - WHITEBOARD_COLLAB_SERVER_URL_BASE networks: meet.jitsi: depends_on: @@ -180,7 +180,7 @@ services: # XMPP server prosody: - image: jitsi/prosody:${JITSI_IMAGE_VERSION:-stable-9457-2} + image: jitsi/prosody:${JITSI_IMAGE_VERSION:-stable-9646} restart: ${RESTART_POLICY:-unless-stopped} expose: - '${XMPP_PORT:-5222}' @@ -261,10 +261,13 @@ services: - PROSODY_RESERVATION_ENABLED - PROSODY_RESERVATION_REST_BASE_URL - PROSODY_ENABLE_RATE_LIMITS + - PROSODY_ENABLE_STANZA_COUNTS - PROSODY_ENABLE_S2S + - PROSODY_ENABLE_METRICS - PROSODY_GUEST_AUTH_TYPE - PROSODY_HTTP_PORT - PROSODY_LOG_CONFIG + - PROSODY_METRICS_ALLOWED_CIDR - PROSODY_MODE - PROSODY_RATE_LIMIT_LOGIN_RATE - PROSODY_RATE_LIMIT_SESSION_RATE @@ -313,7 +316,7 @@ services: # Focus component jicofo: - image: jitsi/jicofo:${JITSI_IMAGE_VERSION:-stable-9457-2} + image: jitsi/jicofo:${JITSI_IMAGE_VERSION:-stable-9646} restart: ${RESTART_POLICY:-unless-stopped} ports: - '127.0.0.1:${JICOFO_REST_PORT:-8888}:8888' @@ -397,7 +400,7 @@ services: # Video bridge jvb: - image: jitsi/jvb:${JITSI_IMAGE_VERSION:-stable-9457-2} + image: jitsi/jvb:${JITSI_IMAGE_VERSION:-stable-9646} restart: ${RESTART_POLICY:-unless-stopped} ports: - '${JVB_PORT:-10000}:${JVB_PORT:-10000}/udp' @@ -418,12 +421,15 @@ services: - ENABLE_COLIBRI_WEBSOCKET - ENABLE_JVB_XMPP_SERVER - ENABLE_OCTO + - ENABLE_SCTP - JVB_ADVERTISE_IPS - JVB_ADVERTISE_PRIVATE_CANDIDATES - JVB_AUTH_USER - JVB_AUTH_PASSWORD - JVB_BREWERY_MUC + - JVB_CC_TRUST_BWE - JVB_DISABLE_STUN + - JVB_DISABLE_XMPP - JVB_INSTANCE_ID - JVB_PORT - JVB_MUC_NICKNAME @@ -433,6 +439,7 @@ services: - JVB_OCTO_REGION - JVB_OCTO_RELAY_ID - JVB_REQUIRE_VALID_ADDRESS + - JVB_USE_USRSCTP - JVB_WS_DOMAIN - JVB_WS_SERVER_ID - JVB_ENABLE_WS_COMPRESSION diff --git a/env.example b/env.example index 30dafb31a9..dd8c50a847 100644 --- a/env.example +++ b/env.example @@ -73,23 +73,22 @@ TZ=UTC # Etherpad integration (for document sharing) # -# Set etherpad-lite URL in docker local network (uncomment to enable) +# Set the etherpad-lite URL in the docker local network (uncomment to enable) #ETHERPAD_URL_BASE=http://etherpad.meet.jitsi:9001 # Set etherpad-lite public URL, including /p/ pad path fragment (uncomment to enable) #ETHERPAD_PUBLIC_URL=https://etherpad.my.domain/p/ -# Name your etherpad instance! -ETHERPAD_TITLE="Video Chat" -# The default text of a pad -ETHERPAD_DEFAULT_PAD_TEXT="Welcome to Web Chat!\n\n" +# +# Whiteboard integration +# -# Name of the skin for etherpad -ETHERPAD_SKIN_NAME=colibris +# Set the excalidraw-backend URL in the docker local network (uncomment to enable) +#WHITEBOARD_COLLAB_SERVER_URL_BASE=http://whiteboard.meet.jitsi -# Skin variants for etherpad -ETHERPAD_SKIN_VARIANTS="super-light-toolbar super-light-editor light-background full-width-editor" +# Set the excalidraw-backend public URL (uncomment to enable) +#WHITEBOARD_COLLAB_SERVER_PUBLIC_URL=https://whiteboard.meet.my.domain # diff --git a/etherpad.yml b/etherpad.yml index e6bd397022..a6eb692a2c 100644 --- a/etherpad.yml +++ b/etherpad.yml @@ -3,13 +3,13 @@ version: '3.5' services: # Etherpad: real-time collaborative document editing etherpad: - image: etherpad/etherpad:1.9.6 + image: etherpad/etherpad:2.0.3 restart: ${RESTART_POLICY:-unless-stopped} environment: - - TITLE=${ETHERPAD_TITLE} - - DEFAULT_PAD_TEXT=${ETHERPAD_DEFAULT_PAD_TEXT} - - SKIN_NAME=${ETHERPAD_SKIN_NAME} - - SKIN_VARIANTS=${ETHERPAD_SKIN_VARIANTS} + - TITLE=${ETHERPAD_TITLE:-""} + - DEFAULT_PAD_TEXT=${ETHERPAD_DEFAULT_PAD_TEXT:-""} + - SKIN_NAME=${ETHERPAD_SKIN_NAME:-colibris} + - SKIN_VARIANTS=${ETHERPAD_SKIN_VARIANTS:-"super-light-toolbar super-light-editor light-background full-width-editor"} - SUPPRESS_ERRORS_IN_PAD_TEXT=true networks: meet.jitsi: diff --git a/grafana.yml b/grafana.yml new file mode 100644 index 0000000000..63b5b5bc67 --- /dev/null +++ b/grafana.yml @@ -0,0 +1,13 @@ +version: '3.5' + +services: + # Grafana: used for visualization of metrics and log data through customizable dashboards. + grafana: + image: grafana/grafana:10.2.0 + environment: + - GF_ANALYTICS_REPORTING_ENABLED=false + volumes: + - ./log-analyser/grafana:/var/lib/grafana + - ./log-analyser/grafana-provisioning/dashboards/:/etc/grafana/provisioning/dashboards/ + ports: + - "3000:3000" diff --git a/jibri.yml b/jibri.yml index f88f665282..bc637ba96f 100644 --- a/jibri.yml +++ b/jibri.yml @@ -2,7 +2,7 @@ version: '3.5' services: jibri: - image: jitsi/jibri:${JITSI_IMAGE_VERSION:-stable-9457-2} + image: jitsi/jibri:${JITSI_IMAGE_VERSION:-stable-9646} restart: ${RESTART_POLICY:-unless-stopped} volumes: - ${CONFIG}/jibri:/config:Z diff --git a/jibri/Dockerfile b/jibri/Dockerfile index 2e90d2271c..a99d01401c 100644 --- a/jibri/Dockerfile +++ b/jibri/Dockerfile @@ -11,12 +11,26 @@ LABEL org.opencontainers.image.documentation="https://jitsi.github.io/handbook/" ARG USE_CHROMIUM=0 #ARG CHROME_RELEASE=latest # https://googlechromelabs.github.io/chrome-for-testing/ -ARG CHROME_RELEASE=121.0.6167.85 +ARG CHROME_RELEASE=126.0.6478.126 COPY rootfs/ / RUN apt-dpkg-wrap apt-get update && \ - apt-dpkg-wrap apt-get install -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" jibri libgl1-mesa-dri procps jitsi-upload-integrations jitsi-autoscaler-sidecar jq pulseaudio dbus dbus-x11 rtkit unzip fonts-noto && \ + apt-dpkg-wrap apt-get install -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" \ + jibri \ + libgl1-mesa-dri \ + procps \ + jitsi-upload-integrations \ + jitsi-autoscaler-sidecar \ + jq \ + pulseaudio \ + dbus \ + dbus-x11 \ + rtkit \ + unzip \ + fonts-noto \ + fonts-noto-cjk \ + libcap2-bin && \ /usr/bin/install-chrome.sh && \ apt-cleanup && \ adduser jibri rtkit && \ diff --git a/jibri/rootfs/defaults/autoscaler-sidecar.config b/jibri/rootfs/defaults/autoscaler-sidecar.config index a83173f1c5..d40d3f3941 100644 --- a/jibri/rootfs/defaults/autoscaler-sidecar.config +++ b/jibri/rootfs/defaults/autoscaler-sidecar.config @@ -5,7 +5,7 @@ export SHUTDOWN_POLLING_INTERVAL={{ $SHUTDOWN_POLLING_INTERVAL }} export STATS_POLLING_INTERVAL={{ $STATS_POLLING_INTERVAL }} export PORT={{ .Env.AUTOSCALER_SIDECAR_PORT }} export GRACEFUL_SHUTDOWN_SCRIPT="/opt/jitsi/jibri/wait_graceful_shutdown.sh" -export TERMINATE_SCRIPT="/opt/jitsi/jibri/shutdown.sh" +export TERMINATE_SCRIPT="/opt/jitsi/shutdown.sh" export ENABLE_REPORT_STATS=true export POLLING_URL="{{ .Env.AUTOSCALER_URL }}/sidecar/poll" export STATUS_URL="{{ .Env.AUTOSCALER_URL }}/sidecar/status" diff --git a/jibri/rootfs/defaults/jibri.conf b/jibri/rootfs/defaults/jibri.conf index 0bf9a82264..0eac063006 100644 --- a/jibri/rootfs/defaults/jibri.conf +++ b/jibri/rootfs/defaults/jibri.conf @@ -1,3 +1,4 @@ +{{ $IGNORE_CERTIFICATE_ERRORS := .Env.IGNORE_CERTIFICATE_ERRORS | default "false" | toBool -}} {{ $ENABLE_PROMETHEUS := .Env.JIBRI_ENABLE_PROMETHEUS | default "false" | toBool -}} {{ $JIBRI_RECORDING_RESOLUTION := .Env.JIBRI_RECORDING_RESOLUTION | default "1280x720" -}} {{ $JIBRI_RECORDING_VIDEO_ENCODE_PRESET := .Env.JIBRI_RECORDING_VIDEO_ENCODE_PRESET | default "veryfast" -}} @@ -64,7 +65,7 @@ jibri { "{{ join "\",\"" (splitList "," .Env.CHROMIUM_FLAGS) }}" ] } - {{ else if .Env.IGNORE_CERTIFICATE_ERRORS -}} + {{ else if $IGNORE_CERTIFICATE_ERRORS -}} chrome { flags = [ "--use-fake-ui-for-media-stream", diff --git a/jibri/rootfs/defaults/xorg-video-dummy.conf b/jibri/rootfs/defaults/xorg-video-dummy.conf index 7bb095d7c9..37e56c4ffa 100644 --- a/jibri/rootfs/defaults/xorg-video-dummy.conf +++ b/jibri/rootfs/defaults/xorg-video-dummy.conf @@ -1,6 +1,6 @@ {{ $JIBRI_RECORDING_RESOLUTION := .Env.JIBRI_RECORDING_RESOLUTION | default "1280x720" -}} -{{ $JIBRI_HORIZ_SYNC := .Env.JIBRI_XORG_HORIZ_SYNC | default "43.0 - 47.0" -}} -{{ $JIBRI_VERT_REFRESH := .Env.JIBRI_XORG_VERT_REFRESH | default "58.0 - 62.0" -}} +{{ $JIBRI_HORIZ_SYNC := .Env.JIBRI_XORG_HORIZ_SYNC | default "5.0 - 1000.0" -}} +{{ $JIBRI_VERT_REFRESH := .Env.JIBRI_XORG_VERT_REFRESH | default "5.0 - 200.0" -}} # This xorg configuration file is meant to be used by xpra # to start a dummy X11 server. @@ -65,7 +65,6 @@ Section "Monitor" Modeline "1360x768" 24.49 1360 1392 1480 1512 768 786 789 807 Modeline "1024x768" 18.71 1024 1056 1120 1152 768 786 789 807 Modeline "768x1024" 19.50 768 800 872 904 1024 1048 1052 1076 - Modeline "1280x720@60" 73.78 1280 1312 1592 1624 720 735 742 757 #common resolutions for android devices (both orientations): @@ -113,8 +112,7 @@ Section "Screen" SubSection "Display" Viewport 0 0 Depth 24 - Modes "5120x3200" "3840x2880" "3840x2560" "3840x2048" "2048x2048" "2560x1600" "1920x1440" "1920x1200" "1920x1080" "1600x1200" "1680x1050" "1600x900" "1400x1050" "1440x900" "1280x1024" "1366x768" "1280x800" "1024x768" "1024x600" "800x600" "320x200" - Virtual {{ join " " (splitList "x" $JIBRI_RECORDING_RESOLUTION) }} + Modes {{ $JIBRI_RECORDING_RESOLUTION | quote }} EndSubSection EndSection diff --git a/jibri/rootfs/etc/cont-init.d/10-config b/jibri/rootfs/etc/cont-init.d/10-config index 7f9a0ceb87..d1ea95cba2 100644 --- a/jibri/rootfs/etc/cont-init.d/10-config +++ b/jibri/rootfs/etc/cont-init.d/10-config @@ -1,5 +1,11 @@ #!/usr/bin/with-contenv bash +# Check if the SYS_ADMIN cap is set +if ! capsh --has-p=cap_sys_admin; then + echo "Required capability SYS_ADMIN is missing" + exit 1 +fi + # Check if /dev/shm is large enough (2GB at least) if ! shm-check; then echo "/dev/shm must be at least 2GB in size" diff --git a/jibri/rootfs/opt/jitsi/shutdown.sh b/jibri/rootfs/opt/jitsi/shutdown.sh new file mode 100755 index 0000000000..1cc01e4081 --- /dev/null +++ b/jibri/rootfs/opt/jitsi/shutdown.sh @@ -0,0 +1,11 @@ +#!/usr/bin/with-contenv bash +# notify the sidecar of imminent shutdown +PORT=${AUTOSCALER_SIDECAR_PORT:-6000} +curl -d '{}' -v 0:$PORT/hook/v1/shutdown +sleep 10 + +# signal jibri to shutdown via rest api +/opt/jitsi/jibri/shutdown.sh + +# shutdown everything else +s6-svscanctl -t /var/run/s6/services diff --git a/jicofo/rootfs/defaults/jicofo.conf b/jicofo/rootfs/defaults/jicofo.conf index 5ee4b32e51..aab5cf21eb 100644 --- a/jicofo/rootfs/defaults/jicofo.conf +++ b/jicofo/rootfs/defaults/jicofo.conf @@ -4,15 +4,16 @@ {{ $AUTH_TYPE := .Env.AUTH_TYPE | default "internal" -}} {{ $JICOFO_AUTH_TYPE := .Env.JICOFO_AUTH_TYPE | default $AUTH_TYPE -}} {{ $JICOFO_AUTH_LIFETIME := .Env.JICOFO_AUTH_LIFETIME | default "24 hours" -}} -{{ $ENABLE_SCTP := .Env.ENABLE_SCTP | default "0" | toBool -}} +{{ $ENABLE_SCTP := .Env.ENABLE_SCTP | default "1" | toBool -}} {{ $ENABLE_RECORDING := .Env.ENABLE_RECORDING | default "0" | toBool -}} {{ $ENABLE_OCTO := .Env.ENABLE_OCTO | default "0" | toBool -}} -{{ $ENABLE_OCTO_SCTP := .Env.ENABLE_OCTO_SCTP | default (.Env.ENABLE_SCTP | default "0") | toBool -}} +{{ $ENABLE_OCTO_SCTP := .Env.ENABLE_OCTO_SCTP | default $ENABLE_SCTP | toBool -}} {{ $ENABLE_AUTO_LOGIN := .Env.ENABLE_AUTO_LOGIN | default "1" | toBool -}} {{ $ENABLE_REST := .Env.JICOFO_ENABLE_REST | default "0" | toBool -}} {{ $ENABLE_JVB_XMPP_SERVER := .Env.ENABLE_JVB_XMPP_SERVER | default "0" | toBool -}} {{ $HEALTH_CHECKS_USE_PRESENCE := .Env.JICOFO_HEALTH_CHECKS_USE_PRESENCE | default "0" | toBool -}} {{ $JIBRI_BREWERY_MUC := .Env.JIBRI_BREWERY_MUC | default "jibribrewery" -}} +{{ $ENABLE_TRANSCRIPTIONS := .Env.ENABLE_TRANSCRIPTIONS | default "0" | toBool -}} {{ $JIGASI_BREWERY_MUC := .Env.JIGASI_BREWERY_MUC | default "jigasibrewery" -}} {{ $JVB_BREWERY_MUC := .Env.JVB_BREWERY_MUC | default "jvbbrewery" -}} {{ $JIBRI_PENDING_TIMEOUT := .Env.JIBRI_PENDING_TIMEOUT | default "90 seconds" -}} @@ -27,7 +28,7 @@ {{ $VISITORS_XMPP_DOMAIN := .Env.VISITORS_XMPP_DOMAIN | default "meet.jitsi" -}} {{ $VISITORS_XMPP_SERVER := .Env.VISITORS_XMPP_SERVER | default "" -}} {{ $VISITORS_XMPP_SERVERS := splitList "," $VISITORS_XMPP_SERVER -}} -{{ $VISITORS_XMPP_PORT := .Env.VISITORS_XMPP_PORT | default "52220" }} +{{ $VISITORS_XMPP_PORT := .Env.VISITORS_XMPP_PORT | default 52220 }} {{ $XMPP_AUTH_DOMAIN := .Env.XMPP_AUTH_DOMAIN | default "auth.meet.jitsi" -}} {{ $XMPP_MUC_DOMAIN := .Env.XMPP_MUC_DOMAIN | default "muc.meet.jitsi" -}} {{ $XMPP_INTERNAL_MUC_DOMAIN := .Env.XMPP_INTERNAL_MUC_DOMAIN | default "internal-muc.meet.jitsi" -}} @@ -204,7 +205,7 @@ jicofo { } {{ end }} - {{ if and .Env.JIGASI_SIP_URI $JIGASI_BREWERY_MUC }} + {{ if or .Env.JIGASI_SIP_URI $ENABLE_TRANSCRIPTIONS }} jigasi { brewery-jid = "{{ $JIGASI_BREWERY_MUC }}@{{ $XMPP_INTERNAL_MUC_DOMAIN }}" } @@ -290,8 +291,8 @@ jicofo { disable-certificate-verification = true } {{ end }} - + trusted-domains = [ {{ range $index, $element := $TRUSTED_DOMAINS }}{{ if gt $index 0 }},{{ end }}"{{ $element }}"{{ end}} ] - + } } diff --git a/jicofo/rootfs/usr/local/bin/healthcheck.sh b/jicofo/rootfs/usr/local/bin/healthcheck.sh new file mode 100755 index 0000000000..cab491a29c --- /dev/null +++ b/jicofo/rootfs/usr/local/bin/healthcheck.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +curl --fail-with-body http://127.0.0.1:8888/about/health diff --git a/jigasi.yml b/jigasi.yml index 7aade4d6d3..c993930d49 100644 --- a/jigasi.yml +++ b/jigasi.yml @@ -3,7 +3,7 @@ version: '3.5' services: # SIP gateway (audio) jigasi: - image: jitsi/jigasi:${JITSI_IMAGE_VERSION:-stable-9457-2} + image: jitsi/jigasi:${JITSI_IMAGE_VERSION:-stable-9646} restart: ${RESTART_POLICY:-unless-stopped} ports: - '${JIGASI_PORT_MIN:-20000}-${JIGASI_PORT_MAX:-20050}:${JIGASI_PORT_MIN:-20000}-${JIGASI_PORT_MAX:-20050}/udp' @@ -21,6 +21,7 @@ services: - AUTOSCALER_SIDECAR_SHUTDOWN_POLLING_INTERVAL - AUTOSCALER_SIDECAR_STATS_POLLING_INTERVAL - AUTOSCALER_URL + - BOSH_URL_PATTERN - ENABLE_AUTH - ENABLE_GUESTS - XMPP_AUTH_DOMAIN @@ -31,7 +32,10 @@ services: - XMPP_PORT - XMPP_DOMAIN - PUBLIC_URL + - JIGASI_CONFIGURATION - JIGASI_DISABLE_SIP + - JIGASI_JVB_TIMEOUT + - JIGASI_LOCAL_REGION - JIGASI_LOG_FILE - JIGASI_SIP_URI - JIGASI_SIP_PASSWORD @@ -63,6 +67,7 @@ services: - SENTRY_ENVIRONMENT - SENTRY_RELEASE - TZ + - USE_TRANSLATOR_IN_CONFERENCE depends_on: - prosody networks: diff --git a/jigasi/rootfs/defaults/sip-communicator.properties b/jigasi/rootfs/defaults/sip-communicator.properties index ea5bf07d62..850d1af833 100644 --- a/jigasi/rootfs/defaults/sip-communicator.properties +++ b/jigasi/rootfs/defaults/sip-communicator.properties @@ -1,6 +1,10 @@ {{ $ENABLE_TRANSCRIPTIONS := .Env.ENABLE_TRANSCRIPTIONS | default "0" | toBool -}} {{ $JIGASI_BREWERY_MUC := .Env.JIGASI_BREWERY_MUC | default "jigasibrewery" -}} {{ $JIGASI_XMPP_USER := .Env.JIGASI_XMPP_USER | default "jigasi" -}} +{{ $JIGASI_JVB_TIMEOUT := .Env.JIGASI_JVB_TIMEOUT | default "30000" -}} +{{ $JIGASI_LOCAL_REGION := .Env.JIGASI_LOCAL_REGION | default "" -}} +{{ $BOSH_URL_PATTERN := .Env.BOSH_URL_PATTERN | default "" -}} +{{ $USE_TRANSLATOR_IN_CONFERENCE := .Env.USE_TRANSLATOR_IN_CONFERENCE | default "0" | toBool -}} {{ $XMPP_AUTH_DOMAIN := .Env.XMPP_AUTH_DOMAIN | default "auth.meet.jitsi" -}} {{ $XMPP_MUC_DOMAIN := .Env.XMPP_MUC_DOMAIN | default "muc.meet.jitsi" -}} {{ $XMPP_GUEST_DOMAIN := .Env.XMPP_GUEST_DOMAIN | default "guest.meet.jitsi" -}} @@ -187,3 +191,24 @@ org.jitsi.jigasi.MUC_SERVICE_ADDRESS={{ $XMPP_MUC_DOMAIN }} {{ if $TRUSTED_DOMAIN_LIST }} org.jitsi.jigasi.TRUSTED_DOMAINS=[ {{ range $index, $element := $TRUSTED_DOMAINS }}{{ if gt $index 0 }},{{ end }}"{{ $element }}"{{ end}} ] {{ end }} + +org.jitsi.jigasi.JVB_INVITE_TIMEOUT={{ $JIGASI_JVB_TIMEOUT }} + +{{ if $JIGASI_LOCAL_REGION }} +org.jitsi.jigasi.LOCAL_REGION={{ $JIGASI_LOCAL_REGION }} +{{ end }} + +{{ if $BOSH_URL_PATTERN }} +org.jitsi.jigasi.xmpp.acc.BOSH_URL_PATTERN={{ $BOSH_URL_PATTERN }} +{{ end }} + +{{ if $USE_TRANSLATOR_IN_CONFERENCE }} +org.jitsi.jigasi.xmpp.acc.USE_TRANSLATOR_IN_CONFERENCE=true +net.java.sip.communicator.impl.protocol.sip.acc1.USE_TRANSLATOR_IN_CONFERENCE=true +# Should be enabled when using translator mode +net.java.sip.communicator.impl.neomedia.audioSystem.audiosilence.captureDevice_list=["AudioSilenceCaptureDevice:noTransferData"] +{{ end }} + +{{ if .Env.JIGASI_CONFIGURATION -}} +{{ join "\n" (splitList "," .Env.JIGASI_CONFIGURATION) }} +{{ end -}} diff --git a/jigasi/rootfs/usr/local/bin/healthcheck.sh b/jigasi/rootfs/usr/local/bin/healthcheck.sh new file mode 100755 index 0000000000..47061c6486 --- /dev/null +++ b/jigasi/rootfs/usr/local/bin/healthcheck.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +curl --fail-with-body http://127.0.0.1:8788/about/health diff --git a/jvb/rootfs/defaults/jvb.conf b/jvb/rootfs/defaults/jvb.conf index a5070371cd..1bf0cd77f4 100644 --- a/jvb/rootfs/defaults/jvb.conf +++ b/jvb/rootfs/defaults/jvb.conf @@ -1,11 +1,14 @@ {{ $COLIBRI_REST_ENABLED := .Env.COLIBRI_REST_ENABLED | default "false" | toBool -}} -{{ $ENABLE_COLIBRI_WEBSOCKET := .Env.ENABLE_COLIBRI_WEBSOCKET | default "1" | toBool -}} +{{ $DISABLE_XMPP := .Env.JVB_DISABLE_XMPP | default "0" | toBool -}} +{{ $ENABLE_COLIBRI_WEBSOCKET := .Env.ENABLE_COLIBRI_WEBSOCKET | default "0" | toBool -}} {{ $ENABLE_OCTO := .Env.ENABLE_OCTO | default "0" | toBool -}} +{{ $ENABLE_SCTP := .Env.ENABLE_SCTP | default "1" | toBool -}} {{ $ENABLE_JVB_XMPP_SERVER := .Env.ENABLE_JVB_XMPP_SERVER | default "0" | toBool }} {{ $JVB_DISABLE_STUN := .Env.JVB_DISABLE_STUN | default "0" | toBool -}} {{ $JVB_STUN_SERVERS := .Env.JVB_STUN_SERVERS | default "meet-jit-si-turnrelay.jitsi.net:443" -}} {{ $JVB_AUTH_USER := .Env.JVB_AUTH_USER | default "jvb" -}} {{ $JVB_BREWERY_MUC := .Env.JVB_BREWERY_MUC | default "jvbbrewery" -}} +{{ $JVB_CC_TRUST_BWE := .Env.JVB_CC_TRUST_BWE | default "true" | toBool -}} {{ $JVB_MUC_NICKNAME := .Env.JVB_MUC_NICKNAME | default .Env.HOSTNAME -}} {{ $JVB_ADVERTISE_PRIVATE_CANDIDATES := .Env.JVB_ADVERTISE_PRIVATE_CANDIDATES | default "true" | toBool -}} {{ $JVB_ADVERTISE_IPS := .Env.JVB_ADVERTISE_IPS | default "" -}} @@ -18,8 +21,10 @@ {{ $JVB_XMPP_SERVERS := splitList "," $JVB_XMPP_SERVER -}} {{ $PUBLIC_URL_DOMAIN := .Env.PUBLIC_URL | default "https://localhost:8443" | trimPrefix "https://" | trimSuffix "/" -}} {{ $SHUTDOWN_REST_ENABLED := .Env.SHUTDOWN_REST_ENABLED | default "false" | toBool -}} +{{ $USE_USRSCTP := .Env.JVB_USE_USRSCTP | default "false" | toBool -}} {{ $WS_DOMAIN := .Env.JVB_WS_DOMAIN | default $PUBLIC_URL_DOMAIN -}} -{{ $WS_SERVER_ID := .Env.JVB_WS_SERVER_ID | default .Env.JVB_WS_SERVER_ID_FALLBACK -}} +{{ $WS_SERVER_ID := .Env.JVB_WS_SERVER_ID | default .Env.JVB_WS_SERVER_ID_FALLBACK | default "default" -}} +{{ $WS_TLS := .Env.JVB_WS_TLS | default "1" | toBool -}} {{ $ENABLE_WS_COMPRESSION := .Env.JVB_ENABLE_WS_COMPRESSION | default "1" | toBool -}} {{ $XMPP_AUTH_DOMAIN := .Env.XMPP_AUTH_DOMAIN | default "auth.meet.jitsi" -}} {{ $XMPP_INTERNAL_MUC_DOMAIN := .Env.XMPP_INTERNAL_MUC_DOMAIN | default "internal-muc.meet.jitsi" -}} @@ -30,6 +35,9 @@ {{ $ENV := .Env -}} videobridge { + cc { + trust-bwe = {{ $JVB_CC_TRUST_BWE }} + } ice { udp { port = {{ .Env.JVB_PORT | default 10000 }} @@ -37,6 +45,7 @@ videobridge { advertise-private-candidates = {{ $JVB_ADVERTISE_PRIVATE_CANDIDATES }} } apis { +{{ if not $DISABLE_XMPP -}} xmpp-client { configs { {{ if $ENABLE_JVB_XMPP_SERVER }} @@ -67,9 +76,10 @@ videobridge { DISABLE_CERTIFICATE_VERIFICATION = true } {{ end -}} -{{ end }} +{{ end -}} } } +{{ end -}} rest { enabled = {{ $COLIBRI_REST_ENABLED }} } @@ -79,13 +89,17 @@ videobridge { enabled = {{ $SHUTDOWN_REST_ENABLED }} } } + sctp { + enabled = {{ $ENABLE_SCTP }} + use-usrsctp = {{ $USE_USRSCTP }} + } stats { enabled = true } websockets { enabled = {{ $ENABLE_COLIBRI_WEBSOCKET }} domain = "{{ $WS_DOMAIN }}" - tls = true + tls = {{ $WS_TLS }} enable-compression = {{ $ENABLE_WS_COMPRESSION }} server-id = "{{ $WS_SERVER_ID }}" } diff --git a/jvb/rootfs/etc/cont-init.d/10-config b/jvb/rootfs/etc/cont-init.d/10-config index 5e65dff575..1a001fbe94 100644 --- a/jvb/rootfs/etc/cont-init.d/10-config +++ b/jvb/rootfs/etc/cont-init.d/10-config @@ -1,17 +1,24 @@ #!/usr/bin/with-contenv bash -if [[ -z $JVB_AUTH_PASSWORD ]]; then - echo 'FATAL ERROR: JVB auth password must be set' - exit 1 -fi +if [[ -z $JVB_DISABLE_XMPP ]]; then + if [[ -z $JVB_AUTH_PASSWORD ]]; then + echo 'FATAL ERROR: JVB auth password must be set' + exit 1 + fi -OLD_JVB_AUTH_PASSWORD=passw0rd -if [[ "$JVB_AUTH_PASSWORD" == "$OLD_JVB_AUTH_PASSWORD" ]]; then - echo 'FATAL ERROR: JVB auth password must be changed, check the README' - exit 1 -fi + OLD_JVB_AUTH_PASSWORD=passw0rd + if [[ "$JVB_AUTH_PASSWORD" == "$OLD_JVB_AUTH_PASSWORD" ]]; then + echo 'FATAL ERROR: JVB auth password must be changed, check the README' + exit 1 + fi -[ -z "${XMPP_SERVER}" ] && export XMPP_SERVER=xmpp.meet.jitsi + [ -z "${XMPP_SERVER}" ] && export XMPP_SERVER=xmpp.meet.jitsi + + # On environments like Swarm the IP address used by the default gateway need not be + # the one used for inter-container traffic. Use that one for our fallback ID. + XMPP_SERVER_IP=$(dig +short +search ${XMPP_SERVER}) + export JVB_WS_SERVER_ID_FALLBACK=$(ip route get ${XMPP_SERVER_IP} | grep -oP '(?<=src ).*' | awk '{ print $1 '}) +fi # Migration from DOCKER_HOST_ADDRESS to JVB_ADVERTISE_IPS if [[ -z "${JVB_ADVERTISE_IPS}" ]]; then @@ -21,11 +28,6 @@ if [[ -z "${JVB_ADVERTISE_IPS}" ]]; then fi fi -# On environments like Swarm the IP address used by the default gateway need not be -# the one used for inter-container traffic. Use that one for our fallback ID. -XMPP_SERVER_IP=$(dig +short +search ${XMPP_SERVER}) -export JVB_WS_SERVER_ID_FALLBACK=$(ip route get ${XMPP_SERVER_IP} | grep -oP '(?<=src ).*' | awk '{ print $1 '}) - # Local IP for the ice4j mapping harvester. export LOCAL_ADDRESS=$(ip route get 1 | grep -oP '(?<=src ).*' | awk '{ print $1 '}) @@ -72,9 +74,3 @@ tpl /defaults/logging.properties > /config/logging.properties tpl /defaults/jvb.conf > /config/jvb.conf chown -R jvb:jitsi /config - -# Configuration checks -if [[ (-z $ENABLE_COLIBRI_WEBSOCKET || $ENABLE_COLIBRI_WEBSOCKET == "0") && $ENABLE_OCTO == "1" ]]; then - echo "ERROR: In order to enable Octo relays (with ENABLE_OCTO=1), you MUST enable Colibri websockets (with ENABLE_COLIBRI_WEBSOCKET=1)"; - exit 1; -fi diff --git a/jvb/rootfs/opt/jitsi/shutdown.sh b/jvb/rootfs/opt/jitsi/shutdown.sh index d7808909ab..0464acbc97 100755 --- a/jvb/rootfs/opt/jitsi/shutdown.sh +++ b/jvb/rootfs/opt/jitsi/shutdown.sh @@ -1,4 +1,8 @@ #!/usr/bin/with-contenv bash +# notify the sidecar of imminent shutdown +PORT=${AUTOSCALER_SIDECAR_PORT:-6000} +curl -d '{}' -v 0:$PORT/hook/v1/shutdown +sleep 10 # shutdown everything s6-svscanctl -t /var/run/s6/services diff --git a/jvb/rootfs/usr/local/bin/healthcheck.sh b/jvb/rootfs/usr/local/bin/healthcheck.sh new file mode 100755 index 0000000000..401d8c7c7d --- /dev/null +++ b/jvb/rootfs/usr/local/bin/healthcheck.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +curl --fail-with-body http://127.0.0.1:8080/about/health diff --git a/log-analyser.yml b/log-analyser.yml new file mode 100644 index 0000000000..a4fc8ee91a --- /dev/null +++ b/log-analyser.yml @@ -0,0 +1,21 @@ +version: '3.5' + +services: + # Log Analyser: used for setting up a log analysis system for visualization, log collection and log processing. + + loki: + container_name: loki + image: grafana/loki:3.0.0 + command: -config.file=/conf/loki-config.yaml + volumes: + - ./log-analyser/loki/data:/data + - ./log-analyser/loki/conf:/conf + ports: + - "3100:3100" + + otel-collector: + container_name: otel + image: otel/opentelemetry-collector-contrib + volumes: + - ./log-analyser/otel-collector-config.yaml:/etc/otelcol-contrib/config.yaml + - ./log-analyser/jitsi-logs/:/tmp/jitsi-logs/ diff --git a/log-analyser/README.md b/log-analyser/README.md new file mode 100644 index 0000000000..eb47993d9b --- /dev/null +++ b/log-analyser/README.md @@ -0,0 +1,79 @@ +# JITSI MEET LOG ANALYSER - Grafana Loki and OpenTelemetry Integration + +Welcome to the Grafana Loki and OpenTelemetry integration project! This repository provides a simple and effective setup for log management and analysis using Docker, Grafana Loki, and OpenTelemetry. +Currently this is an in-progress GSoC Summer of Code project and so the instructions may change before being finalized. Please treat all this as alpha code. + +## Overview + +This project demonstrates how to configure and use Grafana Loki with OpenTelemetry to collect, parse, and visualize log data. It includes: + +- A Docker Compose setup (`log-analyser.yml`) for Loki and OpenTelemetry Collector. +- A Docker Compose setup (`grafana.yml`) for Grafana. +- Configuration files for log parsing and exporting. +- Instructions to set up and access Grafana with Loki as a data source. +- +## Getting Started + +### Prerequisites + +- Docker +- Docker Compose + +### Setup + +1. **Clone the repository:** + + ```bash + git clone https://github.com/jitsi/docker-jitsi-meet.git + ``` + +### Log Analyser + +1. **Add your log files:** + + Place your log file in the `log-analyser/jitsi-logs` directory. Update the `otel-collector-config.yaml` file with the correct file path to start ingesting the logs. This setup allows OpenTelemetry to read logs from the file and forward them to Loki. + +2. **Update the otel-collector-config.yaml file:** + + Update the file path to point to your log file for ingestion by OpenTelemetry. + +3. **Start the Docker containers:** + + ```bash + docker-compose -f docker-compose.yml -f log-analyser.yml up -d + ``` + +### Grafana + +1. **Start the Docker container:** + + ```bash + docker-compose -f docker-compose.yml -f grafana.yml up -d + ``` + +2. **Access Grafana:** + + Open your web browser and navigate to [http://localhost:3000](http://localhost:3000). + +3. **Log in to Grafana:** + + Use the default credentials: + + ``` + Username: admin + Password: admin + ``` + +### Dashboard Setup + +The dashboard setups are available as JSON files in the `log-analyser/grafana-dashboards` directory. You can import these JSON files into Grafana to use the pre-configured dashboards. In the future, we plan to automate this import process. + + +## Usage + +- **Log Parsing and Visualization:** After setting up, you can use Grafana to explore and visualize your logs. Check our dashboards and panels to monitor log data effectively. + + +## Acknowledgements + +Thanks for checking out this project! If you have any questions or need further assistance, don't hesitate to reach out. diff --git a/log-analyser/grafana-provisioning/dashboards/dashboards.yml b/log-analyser/grafana-provisioning/dashboards/dashboards.yml new file mode 100644 index 0000000000..98128b0629 --- /dev/null +++ b/log-analyser/grafana-provisioning/dashboards/dashboards.yml @@ -0,0 +1,11 @@ +apiVersion: 1 + +providers: +- name: 'default' + orgId: 1 + folder: '' + type: file + disableDeletion: false + editable: true + options: + path: /etc/grafana/provisioning/dashboards diff --git a/log-analyser/grafana-provisioning/dashboards/jicofo.json b/log-analyser/grafana-provisioning/dashboards/jicofo.json new file mode 100644 index 0000000000..2024180cf4 --- /dev/null +++ b/log-analyser/grafana-provisioning/dashboards/jicofo.json @@ -0,0 +1,177 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 1, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "loki", + "uid": "b8130a28-4867-4668-917d-539c93852857" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 2, + "options": { + "displayLabels": [ + "percent" + ], + "legend": { + "calcs": [], + "displayMode": "hidden", + "placement": "right", + "showLegend": false, + "values": [] + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "b8130a28-4867-4668-917d-539c93852857" + }, + "editorMode": "code", + "expr": "sum by (attributes_level) (\n rate({exporter=\"OTLP\"} | json|attributes_log_file_name=\"jicofo.log\"| line_format \"{{.log}}\" | logfmt | pattern \"[<_>] <_level>: <_>\"[5m])\n)", + "legendFormat": "Level: {{attributes_level}}", + "queryType": "range", + "refId": "A" + } + ], + "title": "Log Levels Pie Chart", + "type": "piechart" + }, + { + "datasource": { + "type": "loki", + "uid": "b8130a28-4867-4668-917d-539c93852857" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 1, + "options": { + "displayMode": "lcd", + "minVizHeight": 10, + "minVizWidth": 0, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "valueMode": "color" + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "b8130a28-4867-4668-917d-539c93852857" + }, + "editorMode": "code", + "expr": "sum by (attributes_level, attributes_log_file_name) (\n rate({exporter=\"OTLP\"} | json|attributes_log_file_name=\"jicofo.log\"| line_format \"{{.attributes_message}}\" | logfmt | pattern \"[<_>] #: <_>\"[5m]))", + "legendFormat": "Level: {{attributes_level}}", + "queryType": "range", + "refId": "A" + } + ], + "title": "Log Levels Bar Chart", + "transformations": [], + "type": "bargauge" + } + ], + "refresh": "", + "schemaVersion": 38, + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Jicofo Logs", + "uid": "f2dcfe84-3c27-4b1d-8583-bc2c97a8d22d", + "version": 5, + "weekStart": "" +} diff --git a/log-analyser/grafana-provisioning/dashboards/jitsi-all.json b/log-analyser/grafana-provisioning/dashboards/jitsi-all.json new file mode 100644 index 0000000000..922ad2e12e --- /dev/null +++ b/log-analyser/grafana-provisioning/dashboards/jitsi-all.json @@ -0,0 +1,136 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 3, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "loki", + "uid": "b8130a28-4867-4668-917d-539c93852857" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "barRadius": 0, + "barWidth": 1, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "auto", + "stacking": "none", + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "b8130a28-4867-4668-917d-539c93852857" + }, + "editorMode": "code", + "expr": "sum by (attributes_log_file_name) (\n rate({exporter=\"OTLP\"} | json | line_format \"{{.attributes_message}}\" | logfmt | pattern \"[<_>] <_level>: <_>\"[5m]))", + "legendFormat": "{{attributes_log_file_name}}", + "queryType": "range", + "refId": "A" + } + ], + "title": "Jicofo and JVB Log Counts", + "type": "barchart" + } + ], + "refresh": "", + "schemaVersion": 38, + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Jitsi All Components", + "uid": "b75d666d-4537-45e2-94a1-2783f9362b65", + "version": 1, + "weekStart": "" +} diff --git a/log-analyser/grafana-provisioning/dashboards/jvb.json b/log-analyser/grafana-provisioning/dashboards/jvb.json new file mode 100644 index 0000000000..9a2be5c10e --- /dev/null +++ b/log-analyser/grafana-provisioning/dashboards/jvb.json @@ -0,0 +1,177 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 2, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "loki", + "uid": "b8130a28-4867-4668-917d-539c93852857" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 2, + "options": { + "displayLabels": [ + "percent", + "name" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "b8130a28-4867-4668-917d-539c93852857" + }, + "editorMode": "code", + "expr": "sum by (attributes_level) (\n rate({exporter=\"OTLP\"} | json|attributes_log_file_name=\"jvb.log\"| line_format \"{{.log}}\" | logfmt | pattern \"[<_>] <_level>: <_>\"[5m])\n)", + "legendFormat": "Level: {{attributes_level}}", + "queryType": "range", + "refId": "A" + } + ], + "title": "JVB Log Levels Pie Chart", + "type": "piechart" + }, + { + "datasource": { + "type": "loki", + "uid": "b8130a28-4867-4668-917d-539c93852857" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 1, + "options": { + "displayMode": "lcd", + "minVizHeight": 10, + "minVizWidth": 0, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "valueMode": "color" + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "b8130a28-4867-4668-917d-539c93852857" + }, + "editorMode": "code", + "expr": "sum by (attributes_level, attributes_log_file_name) (\n rate({exporter=\"OTLP\"} | json|attributes_log_file_name=\"jvb.log\"| line_format \"{{.attributes_message}}\" | logfmt | pattern \"[<_>] #: <_>\"[5m]))", + "legendFormat": "Level: {{attributes_level}}", + "queryType": "range", + "refId": "A" + } + ], + "title": "JVB Log Levels Bar Chart", + "type": "bargauge" + } + ], + "refresh": "", + "schemaVersion": 38, + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "JVB Dashboard", + "uid": "d53a9efb-ca3b-4f47-af3a-9638de8a35fa", + "version": 1, + "weekStart": "" +} diff --git a/log-analyser/grafana-provisioning/datasources/datasource_loki.yml b/log-analyser/grafana-provisioning/datasources/datasource_loki.yml new file mode 100644 index 0000000000..6c8883d376 --- /dev/null +++ b/log-analyser/grafana-provisioning/datasources/datasource_loki.yml @@ -0,0 +1,9 @@ +apiVersion: 1 + +datasources: + - name: Loki + isDefault: true + type: loki + access: proxy + url: http://loki:3100 + editable: true \ No newline at end of file diff --git a/log-analyser/loki/conf/loki-config.yaml b/log-analyser/loki/conf/loki-config.yaml new file mode 100644 index 0000000000..0d42a30083 --- /dev/null +++ b/log-analyser/loki/conf/loki-config.yaml @@ -0,0 +1,51 @@ +limits_config: + allow_structured_metadata: true + +auth_enabled: false + +server: + http_listen_port: 3100 + grpc_listen_port: 9096 + +common: + instance_addr: 127.0.0.1 + path_prefix: /tmp/loki + storage: + filesystem: + chunks_directory: /tmp/loki/chunks + rules_directory: /tmp/loki/rules + replication_factor: 1 + ring: + kvstore: + store: inmemory + +query_range: + results_cache: + cache: + embedded_cache: + enabled: true + max_size_mb: 100 + +schema_config: + configs: + - from: 2020-10-24 + store: tsdb + object_store: filesystem + schema: v13 + index: + prefix: index_ + period: 24h + + +# By default, Loki will send anonymous, but uniquely-identifiable usage and configuration +# analytics to Grafana Labs. These statistics are sent to https://stats.grafana.org/ +# +# Statistics help us better understand how Loki is used, and they show us performance +# levels for most users. This helps us prioritize features and documentation. +# For more information on what's sent, look at +# https://github.com/grafana/loki/blob/main/pkg/analytics/stats.go +# Refer to the buildReport method to see what goes into a report. +# +# If you would like to disable reporting, uncomment the following lines: +#analytics: +# reporting_enabled: false diff --git a/log-analyser/otel-collector-config.yaml b/log-analyser/otel-collector-config.yaml new file mode 100644 index 0000000000..d9f1636c68 --- /dev/null +++ b/log-analyser/otel-collector-config.yaml @@ -0,0 +1,53 @@ +receivers: + otlp: + protocols: + http: + grpc: + endpoint: 0.0.0.0:4317 + filelog/jicofo: + include: ['/tmp/jitsi-logs/jicofo.log'] + operators: + - type: regex_parser + regex: "^(?PJicofo) (?P\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{3}) (?P\\w+): \\[(?P\\d+)\\] (?P[\\w\\.]+)#(?P\\d+): (?P[\\S\\s]*)$" + filelog/jvb: + include: ['/tmp/jitsi-logs/jvb.log'] + operators: + - type: regex_parser + regex: "^(?PJVB) (?P\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{3}) (?P\\w+): \\[(?P\\d+)\\] (?P[\\w\\.]+)#(?P\\d+): (?P[\\S\\s]*)$" + filelog/prosody: + include: ['/tmp/jitsi-logs/prosody.log'] + operators: + - type: regex_parser + regex: "^(?P\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2})\\s+(?P\\S+)\\s+(?P\\w+)\\s+(?P.+)$" + filelog/jitsi-web: + include: ['/tmp/jitsi-logs/jitsi-web.log'] + operators: + - type: regex_parser + regex: "^(?P\\[\\w+-\\w+\\.\\w+\\]\\s+(\\w+\\s+)*\\w+:?\\s*.*$)" +processors: + batch: + +exporters: + logging: + loglevel: debug + loki: + endpoint: "http://loki:3100/loki/api/v1/push" + +service: + pipelines: + logs/jicofo: + receivers: [otlp, filelog/jicofo] + processors: [batch] + exporters: [loki] + logs/jvb: + receivers: [otlp, filelog/jvb] + processors: [batch] + exporters: [loki] + logs/prosody: + receivers: [otlp, filelog/prosody] + processors: [batch] + exporters: [loki] + logs/jitsi-web: + receivers: [otlp, filelog/jitsi-web] + processors: [batch] + exporters: [loki] diff --git a/prometheus.yml b/prometheus.yml new file mode 100644 index 0000000000..ffe0bda1c9 --- /dev/null +++ b/prometheus.yml @@ -0,0 +1,13 @@ +services: + prometheus: + image: prom/prometheus + container_name: prometheus + command: + - "--config.file=/etc/prometheus/prometheus.yml" + ports: + - 9090:9090 + restart: ${RESTART_POLICY:-unless-stopped} + volumes: + - ./prometheus:/etc/prometheus + networks: + meet.jitsi: \ No newline at end of file diff --git a/prometheus/prometheus.yml b/prometheus/prometheus.yml new file mode 100644 index 0000000000..b806f42f0a --- /dev/null +++ b/prometheus/prometheus.yml @@ -0,0 +1,5 @@ +scrape_configs: + - job_name: "prometheus" + scrape_interval: 5s + static_configs: + - targets: ["prosody:5280","jvb:8080","jicofo:8888"] diff --git a/prosody/Dockerfile b/prosody/Dockerfile index 633115e3f4..d33c9f7213 100644 --- a/prosody/Dockerfile +++ b/prosody/Dockerfile @@ -57,6 +57,7 @@ RUN wget -qO /etc/apt/trusted.gpg.d/prosody.gpg https://prosody.im/files/prosody rm -rf /usr/share/lua/{5.1,5.2,5.3} && \ wget -qO /prosody-plugins/mod_auth_cyrus.lua https://hg.prosody.im/prosody-modules/raw-file/65438e4ba563/mod_auth_cyrus/mod_auth_cyrus.lua && \ wget -qO /prosody-plugins/sasl_cyrus.lua https://hg.prosody.im/prosody-modules/raw-file/65438e4ba563/mod_auth_cyrus/sasl_cyrus.lua && \ + wget -qO /prosody-plugins/mod_http_health.lua https://hg.prosody.im/prosody-modules/raw-file/2b80188448d1/mod_http_health/mod_http_health.lua && \ wget https://github.com/matrix-org/prosody-mod-auth-matrix-user-verification/archive/refs/tags/v$VERSION_MATRIX_USER_VERIFICATION_SERVICE_PLUGIN.tar.gz && \ tar -xf v$VERSION_MATRIX_USER_VERIFICATION_SERVICE_PLUGIN.tar.gz && \ mv prosody-mod-auth-matrix-user-verification-$VERSION_MATRIX_USER_VERIFICATION_SERVICE_PLUGIN/mod_auth_matrix_user_verification.lua /prosody-plugins && \ diff --git a/prosody/rootfs/defaults/conf.d/jitsi-meet.cfg.lua b/prosody/rootfs/defaults/conf.d/jitsi-meet.cfg.lua index 6ea4e24f6b..22b02c9b9c 100644 --- a/prosody/rootfs/defaults/conf.d/jitsi-meet.cfg.lua +++ b/prosody/rootfs/defaults/conf.d/jitsi-meet.cfg.lua @@ -124,7 +124,6 @@ consider_websocket_secure = true; {{ if $ENABLE_XMPP_WEBSOCKET }} smacks_max_unacked_stanzas = 5; smacks_hibernation_time = 60; -smacks_max_hibernated_sessions = 1; smacks_max_old_sessions = 1; {{ end }} diff --git a/prosody/rootfs/defaults/prosody.cfg.lua b/prosody/rootfs/defaults/prosody.cfg.lua index 74e41d1e2a..3d1b80ce69 100644 --- a/prosody/rootfs/defaults/prosody.cfg.lua +++ b/prosody/rootfs/defaults/prosody.cfg.lua @@ -12,7 +12,10 @@ {{ $GC_GEN_MAX_TH := .Env.GC_GEN_MAX_TH | default 100 -}} {{ $LOG_LEVEL := .Env.LOG_LEVEL | default "info" }} {{ $PROSODY_C2S_LIMIT := .Env.PROSODY_C2S_LIMIT | default "10kb/s" -}} +{{ $PROSODY_METRICS_ALLOWED_CIDR := .Env.PROSODY_METRICS_ALLOWED_CIDR | default "172.16.0.0/12" -}} {{ $PROSODY_HTTP_PORT := .Env.PROSODY_HTTP_PORT | default "5280" -}} +{{ $PROSODY_ENABLE_METRICS := .Env.PROSODY_ENABLE_METRICS | default "false" | toBool -}} +{{ $PROSODY_ENABLE_STANZA_COUNTS := .Env.PROSODY_ENABLE_STANZA_COUNTS | default "false" | toBool -}} {{ $PROSODY_ADMINS := .Env.PROSODY_ADMINS | default "" -}} {{ $PROSODY_ADMIN_LIST := splitList "," $PROSODY_ADMINS -}} {{ $TRUSTED_PROXIES := .Env.PROSODY_TRUSTED_PROXIES | default "127.0.0.1,::1" -}} @@ -23,7 +26,7 @@ {{ $VISITORS_XMPP_DOMAIN := .Env.VISITORS_XMPP_DOMAIN | default "meet.jitsi" -}} {{ $VISITORS_XMPP_SERVER := .Env.VISITORS_XMPP_SERVER | default "" -}} {{ $VISITORS_XMPP_SERVERS := splitList "," $VISITORS_XMPP_SERVER -}} -{{ $VISITORS_XMPP_PORT := .Env.VISITORS_XMPP_PORT | default "52220" }} +{{ $VISITORS_XMPP_PORT := .Env.VISITORS_XMPP_PORT | default 52220 }} {{ $XMPP_DOMAIN := .Env.XMPP_DOMAIN | default "meet.jitsi" -}} {{ $XMPP_GUEST_DOMAIN := .Env.XMPP_GUEST_DOMAIN | default "guest.meet.jitsi" -}} {{ $XMPP_MUC_DOMAIN := .Env.XMPP_MUC_DOMAIN | default "muc.meet.jitsi" -}} @@ -97,6 +100,7 @@ modules_enabled = { --"watchregistrations"; -- Alert admins of registrations --"motd"; -- Send a message to users when they log in --"legacyauth"; -- Legacy authentication. Only used by some old clients and bots. + "http_health"; {{ if eq .Env.PROSODY_MODE "brewery" -}} "firewall"; -- Enable firewalling "secure_interfaces"; @@ -108,6 +112,17 @@ modules_enabled = { "s2sout_override"; "s2s_whitelist"; {{ end -}} + + {{ if $PROSODY_ENABLE_METRICS }} + -- metrics collection functionality + "http_openmetrics"; + {{ end -}} + + {{ if $PROSODY_ENABLE_STANZA_COUNTS }} + -- Stanza count metrics for monitoring + "measure_stanza_counts"; + {{ end -}} + {{ if .Env.GLOBAL_MODULES }} "{{ join "\";\n\"" (splitList "," .Env.GLOBAL_MODULES) }}"; {{ end }} @@ -287,6 +302,13 @@ log = { {{ end }} } +{{ if $PROSODY_ENABLE_METRICS }} +-- Statistics Provider configuration +statistics = "internal" +statistics_interval = "manual" +openmetrics_allow_cidr = "{{ $PROSODY_METRICS_ALLOWED_CIDR }}" +{{ end }} + {{ if .Env.GLOBAL_CONFIG }} {{ join "\n" (splitList "\\n" .Env.GLOBAL_CONFIG) }} {{ end }} diff --git a/prosody/rootfs/usr/local/bin/healthcheck.sh b/prosody/rootfs/usr/local/bin/healthcheck.sh new file mode 100755 index 0000000000..81ac834eed --- /dev/null +++ b/prosody/rootfs/usr/local/bin/healthcheck.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +curl --fail-with-body http://127.0.0.1:5280/health diff --git a/web/rootfs/defaults/meet.conf b/web/rootfs/defaults/meet.conf index a3bc391b20..8cca7565c3 100644 --- a/web/rootfs/defaults/meet.conf +++ b/web/rootfs/defaults/meet.conf @@ -1,4 +1,4 @@ -{{ $ENABLE_COLIBRI_WEBSOCKET := .Env.ENABLE_COLIBRI_WEBSOCKET | default "1" | toBool }} +{{ $ENABLE_COLIBRI_WEBSOCKET := .Env.ENABLE_COLIBRI_WEBSOCKET | default "0" | toBool }} {{ $COLIBRI_WEBSOCKET_PORT := .Env.COLIBRI_WEBSOCKET_PORT | default "9090" }} {{ $COLIBRI_WEBSOCKET_REGEX := .Env.COLIBRI_WEBSOCKET_REGEX | default "jvb" }} {{ $ENABLE_JAAS_COMPONENTS := .Env.ENABLE_JAAS_COMPONENTS | default "0" | toBool }} @@ -134,6 +134,21 @@ location ^~ /etherpad/ { } {{ end }} +{{ if .Env.WHITEBOARD_COLLAB_SERVER_URL_BASE }} +# whiteboard (excalidraw-backend) +location = /socket.io/ { + proxy_buffering off; + proxy_cache_bypass $http_upgrade; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header X-Forwarded-For $remote_addr; + + proxy_pass {{ .Env.WHITEBOARD_COLLAB_SERVER_URL_BASE }}/socket.io/?$args; +} +{{ end }} + location ~ ^/([^/?&:'"]+)$ { try_files $uri @root_path; } diff --git a/web/rootfs/defaults/settings-config.js b/web/rootfs/defaults/settings-config.js index 4a5fbb133b..ff38be0912 100644 --- a/web/rootfs/defaults/settings-config.js +++ b/web/rootfs/defaults/settings-config.js @@ -62,8 +62,7 @@ {{ $ENABLE_LOCAL_RECORDING_SELF_START := .Env.ENABLE_LOCAL_RECORDING_SELF_START | default "false" | toBool -}} {{ $DISABLE_PROFILE := .Env.DISABLE_PROFILE | default "false" | toBool -}} {{ $ROOM_PASSWORD_DIGITS := .Env.ROOM_PASSWORD_DIGITS | default "false" -}} -{{ $WHITEBOARD_COLLAB_SERVER_PUBLIC_URL := .Env.WHITEBOARD_COLLAB_SERVER_PUBLIC_URL | default "" -}} -{{ $WHITEBOARD_ENABLED := .Env.WHITEBOARD_ENABLED | default "false" | toBool -}} +{{ $WHITEBOARD_ENABLED := or (.Env.WHITEBOARD_COLLAB_SERVER_PUBLIC_URL | default "" | toBool) (.Env.WHITEBOARD_COLLAB_SERVER_URL_BASE | default "" | toBool) }} {{ $TESTING_AV1_SUPPORT := .Env.TESTING_AV1_SUPPORT | default "false" | toBool -}} // Video configuration. @@ -554,7 +553,11 @@ config.e2eping.maxMessagePerSecond = {{ .Env.E2EPING_MAX_MESSAGE_PER_SECOND }}; // Settings for the Excalidraw whiteboard integration. config.whiteboard = { enabled: {{ $WHITEBOARD_ENABLED }}, - collabServerBaseUrl: '{{ $WHITEBOARD_COLLAB_SERVER_PUBLIC_URL }}' +{{ if .Env.WHITEBOARD_COLLAB_SERVER_PUBLIC_URL -}} + collabServerBaseUrl: '{{ .Env.WHITEBOARD_COLLAB_SERVER_PUBLIC_URL }}' +{{ else if .Env.WHITEBOARD_COLLAB_SERVER_URL_BASE -}} + collabServerBaseUrl: '{{ $PUBLIC_URL }}' +{{ end -}} }; // Testing diff --git a/web/rootfs/defaults/system-config.js b/web/rootfs/defaults/system-config.js index a4a5ed5524..1a0bff8c97 100644 --- a/web/rootfs/defaults/system-config.js +++ b/web/rootfs/defaults/system-config.js @@ -10,7 +10,7 @@ {{ $XMPP_GUEST_DOMAIN := .Env.XMPP_GUEST_DOMAIN | default "guest.meet.jitsi" -}} {{ $XMPP_MUC_DOMAIN := .Env.XMPP_MUC_DOMAIN | default "muc.meet.jitsi" -}} {{ $XMPP_MUC_DOMAIN_PREFIX := (split "." $XMPP_MUC_DOMAIN)._0 -}} -{{ $JVB_PREFER_SCTP := .Env.JVB_PREFER_SCTP | default "false" | toBool -}} +{{ $JVB_PREFER_SCTP := .Env.JVB_PREFER_SCTP | default "1" | toBool -}} // Jitsi Meet configuration. var config = {}; @@ -67,8 +67,6 @@ config.websocket = 'wss://{{ $PUBLIC_URL_DOMAIN }}/xmpp-websocket'; {{ end -}} {{ end -}} -{{ if $JVB_PREFER_SCTP -}} config.bridgeChannel = { - preferSctp: true + preferSctp: {{ $JVB_PREFER_SCTP }} }; -{{ end -}} diff --git a/whiteboard.yml b/whiteboard.yml new file mode 100644 index 0000000000..9984daf058 --- /dev/null +++ b/whiteboard.yml @@ -0,0 +1,12 @@ +version: '3.5' + +services: + whiteboard: + image: jitsi/excalidraw-backend:21 + restart: ${RESTART_POLICY:-unless-stopped} + depends_on: + - web + networks: + meet.jitsi: + aliases: + - whiteboard.meet.jitsi