mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-07 01:54:09 +00:00
switch from jupyter-telemetry to jupyter-events
- id must be a URL - change `record_event` to `emit`
This commit is contained in:
@@ -1,27 +1,27 @@
|
||||
# Event logging and telemetry
|
||||
|
||||
JupyterHub can be configured to record structured events from a running server using Jupyter's [Telemetry System]. The types of events that JupyterHub emits are defined by [JSON schemas] listed at the bottom of this page.
|
||||
JupyterHub can be configured to record structured events from a running server using Jupyter's [Events System]. The types of events that JupyterHub emits are defined by [JSON schemas] listed at the bottom of this page.
|
||||
|
||||
## How to emit events
|
||||
|
||||
Event logging is handled by its `Eventlog` object. This leverages Python's standing [logging] library to emit, filter, and collect event data.
|
||||
Event logging is handled by its `EventLogger` object. This leverages Python's standing [logging] library to emit, filter, and collect event data.
|
||||
|
||||
To begin recording events, you'll need to set two configurations:
|
||||
|
||||
> 1. `handlers`: tells the EventLog _where_ to route your events. This trait is a list of Python logging handlers that route events to the event log file.
|
||||
> 2. `allows_schemas`: tells the EventLog _which_ events should be recorded. No events are emitted by default; all recorded events must be listed here.
|
||||
> 1. `handlers`: tells the EventLogger _where_ to route your events. This trait is a list of Python logging handlers that route events to the event log file.
|
||||
> 2. `allows_schemas`: tells the EventLogger _which_ events should be recorded. No events are emitted by default; all recorded events must be listed here.
|
||||
|
||||
Here's a basic example:
|
||||
|
||||
```
|
||||
import logging
|
||||
|
||||
c.EventLog.handlers = [
|
||||
c.EventLogger.handlers = [
|
||||
logging.FileHandler('event.log'),
|
||||
]
|
||||
|
||||
c.EventLog.allowed_schemas = [
|
||||
'hub.jupyter.org/server-action'
|
||||
c.EventLogger.allowed_schemas = [
|
||||
'https://schema.jupyter.org/jupyterhub/events/server-action',
|
||||
]
|
||||
```
|
||||
|
||||
@@ -37,6 +37,15 @@ The output is a file, `"event.log"`, with events recorded as JSON data.
|
||||
server-actions
|
||||
```
|
||||
|
||||
:::{versionchanged} 5.0
|
||||
JupyterHub 5.0 changes from the deprecated jupyter-telemetry to jupyter-events.
|
||||
|
||||
The main changes are:
|
||||
|
||||
- `EventLog` configuration is now called `EventLogger`
|
||||
- The `hub.jupyter.org/server-action` schema is now called `https://schema.jupyter.org/jupyterhub/events/server-action`
|
||||
:::
|
||||
|
||||
[json schemas]: https://json-schema.org/
|
||||
[logging]: https://docs.python.org/3/library/logging.html
|
||||
[telemetry system]: https://github.com/jupyter/telemetry
|
||||
[events system]: https://jupyter-events.readthedocs.io
|
||||
|
@@ -21,6 +21,7 @@ from datetime import datetime, timedelta, timezone
|
||||
from functools import partial
|
||||
from getpass import getuser
|
||||
from operator import itemgetter
|
||||
from pathlib import Path
|
||||
from textwrap import dedent
|
||||
from typing import Optional
|
||||
from urllib.parse import unquote, urlparse, urlunparse
|
||||
@@ -29,7 +30,7 @@ import tornado.httpserver
|
||||
import tornado.options
|
||||
from dateutil.parser import parse as parse_date
|
||||
from jinja2 import ChoiceLoader, Environment, FileSystemLoader, PrefixLoader
|
||||
from jupyter_telemetry.eventlog import EventLog
|
||||
from jupyter_events.logger import EventLogger
|
||||
from sqlalchemy.exc import OperationalError, SQLAlchemyError
|
||||
from sqlalchemy.orm import joinedload
|
||||
from tornado import gen, web
|
||||
@@ -3251,13 +3252,10 @@ class JupyterHub(Application):
|
||||
|
||||
def init_eventlog(self):
|
||||
"""Set up the event logging system."""
|
||||
self.eventlog = EventLog(parent=self)
|
||||
self.eventlog = EventLogger(parent=self)
|
||||
|
||||
for dirname, _, files in os.walk(os.path.join(here, 'event-schemas')):
|
||||
for file in files:
|
||||
if not file.endswith('.yaml'):
|
||||
continue
|
||||
self.eventlog.register_schema_file(os.path.join(dirname, file))
|
||||
for schema in (Path(here) / "event-schemas").glob("**/*.yaml"):
|
||||
self.eventlog.register_event_schema(schema)
|
||||
|
||||
def write_pid_file(self):
|
||||
pid = os.getpid()
|
||||
|
@@ -1,4 +1,4 @@
|
||||
"$id": hub.jupyter.org/server-action
|
||||
"$id": https://schema.jupyter.org/jupyterhub/events/server-action
|
||||
version: 1
|
||||
title: JupyterHub server events
|
||||
description: |
|
||||
|
@@ -1128,10 +1128,13 @@ class BaseHandler(RequestHandler):
|
||||
SERVER_SPAWN_DURATION_SECONDS.labels(
|
||||
status=ServerSpawnStatus.success
|
||||
).observe(time.perf_counter() - spawn_start_time)
|
||||
self.eventlog.record_event(
|
||||
'hub.jupyter.org/server-action',
|
||||
1,
|
||||
{'action': 'start', 'username': user.name, 'servername': server_name},
|
||||
self.eventlog.emit(
|
||||
schema_id='https://schema.jupyter.org/jupyterhub/events/server-action',
|
||||
data={
|
||||
'action': 'start',
|
||||
'username': user.name,
|
||||
'servername': server_name,
|
||||
},
|
||||
)
|
||||
proxy_add_start_time = time.perf_counter()
|
||||
spawner._proxy_pending = True
|
||||
@@ -1334,10 +1337,9 @@ class BaseHandler(RequestHandler):
|
||||
SERVER_STOP_DURATION_SECONDS.labels(
|
||||
status=ServerStopStatus.success
|
||||
).observe(toc - tic)
|
||||
self.eventlog.record_event(
|
||||
'hub.jupyter.org/server-action',
|
||||
1,
|
||||
{
|
||||
self.eventlog.emit(
|
||||
schema_id='https://schema.jupyter.org/jupyterhub/events/server-action',
|
||||
data={
|
||||
'action': 'stop',
|
||||
'username': user.name,
|
||||
'servername': server_name,
|
||||
|
@@ -22,7 +22,7 @@ from traitlets.config import Config
|
||||
# { ( '<schema id>', <version> ) : { <event_data> } }
|
||||
valid_events = [
|
||||
(
|
||||
'hub.jupyter.org/server-action',
|
||||
'https://schema.jupyter.org/jupyterhub/events/server-action',
|
||||
1,
|
||||
dict(action='start', username='test-username', servername='test-servername'),
|
||||
)
|
||||
@@ -32,7 +32,11 @@ valid_events = [
|
||||
# { ( '<schema id>', <version> ) : { <event_data> } }
|
||||
invalid_events = [
|
||||
# Missing required keys
|
||||
('hub.jupyter.org/server-action', 1, dict(action='start'))
|
||||
(
|
||||
'https://schema.jupyter.org/jupyterhub/events/server-action',
|
||||
1,
|
||||
dict(action='start'),
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
@@ -41,11 +45,11 @@ def eventlog_sink(app):
|
||||
"""Return eventlog and sink objects"""
|
||||
sink = io.StringIO()
|
||||
handler = logging.StreamHandler(sink)
|
||||
# Update the EventLog config with handler
|
||||
# Update the EventLogger config with handler
|
||||
cfg = Config()
|
||||
cfg.EventLog.handlers = [handler]
|
||||
cfg.EventLogger.handlers = [handler]
|
||||
|
||||
with mock.patch.object(app.config, 'EventLog', cfg.EventLog):
|
||||
with mock.patch.object(app.config, 'EventLogger', cfg.EventLogger):
|
||||
# recreate the eventlog object with our config
|
||||
app.init_eventlog()
|
||||
# return the sink from the fixture
|
||||
@@ -59,7 +63,7 @@ def test_valid_events(eventlog_sink, schema, version, event):
|
||||
eventlog, sink = eventlog_sink
|
||||
eventlog.allowed_schemas = [schema]
|
||||
# Record event
|
||||
eventlog.record_event(schema, version, event)
|
||||
eventlog.emit(schema_id=schema, data=event)
|
||||
# Inspect consumed event
|
||||
output = sink.getvalue()
|
||||
assert output
|
||||
@@ -75,4 +79,4 @@ def test_invalid_events(eventlog_sink, schema, version, event):
|
||||
|
||||
# Make sure an error is thrown when bad events are recorded
|
||||
with pytest.raises(jsonschema.ValidationError):
|
||||
recorded_event = eventlog.record_event(schema, version, event)
|
||||
recorded_event = eventlog.emit(schema_id=schema, data=event)
|
||||
|
@@ -4,7 +4,7 @@ certipy>=0.1.2
|
||||
idna
|
||||
importlib_metadata>=3.6; python_version < '3.10'
|
||||
jinja2>=2.11.0
|
||||
jupyter_telemetry>=0.1.0
|
||||
jupyter_events
|
||||
oauthlib>=3.0
|
||||
packaging
|
||||
pamela>=1.1.0; sys_platform != 'win32'
|
||||
|
Reference in New Issue
Block a user