Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
OpenDAS
dynamo
Commits
5b682f48
Commit
5b682f48
authored
Apr 01, 2025
by
Ryan Olson
Committed by
GitHub
Apr 01, 2025
Browse files
feat: unified logging (#472)
parent
88dd1e11
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
72 additions
and
19 deletions
+72
-19
lib/bindings/python/rust/lib.rs
lib/bindings/python/rust/lib.rs
+10
-9
lib/bindings/python/src/dynamo/_core.pyi
lib/bindings/python/src/dynamo/_core.pyi
+6
-0
lib/runtime/src/config.rs
lib/runtime/src/config.rs
+6
-0
lib/runtime/src/logging.rs
lib/runtime/src/logging.rs
+50
-10
No files found.
lib/bindings/python/rust/lib.rs
View file @
5b682f48
...
@@ -23,10 +23,9 @@ use pyo3::{exceptions::PyException, prelude::*};
...
@@ -23,10 +23,9 @@ use pyo3::{exceptions::PyException, prelude::*};
use
rs
::
pipeline
::
network
::
Ingress
;
use
rs
::
pipeline
::
network
::
Ingress
;
use
std
::{
fmt
::
Display
,
sync
::
Arc
};
use
std
::{
fmt
::
Display
,
sync
::
Arc
};
use
tokio
::
sync
::
Mutex
;
use
tokio
::
sync
::
Mutex
;
use
tracing_subscriber
::
FmtSubscriber
;
use
dynamo_runtime
::{
use
dynamo_runtime
::{
self
as
rs
,
self
as
rs
,
logging
,
pipeline
::{
EngineStream
,
ManyOut
,
SingleIn
},
pipeline
::{
EngineStream
,
ManyOut
,
SingleIn
},
protocols
::
annotated
::
Annotated
as
RsAnnotated
,
protocols
::
annotated
::
Annotated
as
RsAnnotated
,
traits
::
DistributedRuntimeProvider
,
traits
::
DistributedRuntimeProvider
,
...
@@ -50,13 +49,8 @@ const DEFAULT_ANNOTATED_SETTING: Option<bool> = Some(true);
...
@@ -50,13 +49,8 @@ const DEFAULT_ANNOTATED_SETTING: Option<bool> = Some(true);
/// import the module.
/// import the module.
#[pymodule]
#[pymodule]
fn
_
core
(
m
:
&
Bound
<
'_
,
PyModule
>
)
->
PyResult
<
()
>
{
fn
_
core
(
m
:
&
Bound
<
'_
,
PyModule
>
)
->
PyResult
<
()
>
{
// Sets up RUST_LOG environment variable for logging through the python-wheel
logging
::
init
();
// Example: RUST_LOG=debug python3 -m ...
m
.add_function
(
wrap_pyfunction!
(
log_message
,
m
)
?
)
?
;
let
subscriber
=
FmtSubscriber
::
builder
()
.with_env_filter
(
tracing_subscriber
::
EnvFilter
::
from_default_env
())
.finish
();
tracing
::
subscriber
::
set_global_default
(
subscriber
)
.expect
(
"setting default subscriber failed"
);
m
.add_class
::
<
DistributedRuntime
>
()
?
;
m
.add_class
::
<
DistributedRuntime
>
()
?
;
m
.add_class
::
<
CancellationToken
>
()
?
;
m
.add_class
::
<
CancellationToken
>
()
?
;
...
@@ -94,6 +88,13 @@ where
...
@@ -94,6 +88,13 @@ where
PyException
::
new_err
(
format!
(
"{}"
,
err
))
PyException
::
new_err
(
format!
(
"{}"
,
err
))
}
}
/// Log a message from Python with file and line info
#[pyfunction]
#[pyo3(text_signature
=
"(level, message, module, file, line)"
)]
fn
log_message
(
level
:
&
str
,
message
:
&
str
,
module
:
&
str
,
file
:
&
str
,
line
:
u32
)
{
logging
::
log_message
(
level
,
message
,
module
,
file
,
line
);
}
#[pyclass]
#[pyclass]
#[derive(Clone)]
#[derive(Clone)]
struct
DistributedRuntime
{
struct
DistributedRuntime
{
...
...
lib/bindings/python/src/dynamo/_core.pyi
View file @
5b682f48
...
@@ -15,6 +15,12 @@
...
@@ -15,6 +15,12 @@
from typing import AsyncGenerator, AsyncIterator, Callable, Dict, List, Optional
from typing import AsyncGenerator, AsyncIterator, Callable, Dict, List, Optional
def log_message(level: str, message: str, module: str, file: str, line: int) -> None:
"""
Log a message from Python with file and line info
"""
...
class JsonLike:
class JsonLike:
"""
"""
Any PyObject which can be serialized to JSON
Any PyObject which can be serialized to JSON
...
...
lib/runtime/src/config.rs
View file @
5b682f48
...
@@ -170,6 +170,12 @@ pub fn disable_ansi_logging() -> bool {
...
@@ -170,6 +170,12 @@ pub fn disable_ansi_logging() -> bool {
env_is_truthy
(
"DYN_SDK_DISABLE_ANSI_LOGGING"
)
env_is_truthy
(
"DYN_SDK_DISABLE_ANSI_LOGGING"
)
}
}
/// Check whether to use local timezone for logging timestamps (default is UTC)
/// Set the `DYN_LOG_USE_LOCAL_TZ` environment variable to a [`is_truthy`] value
pub
fn
use_local_timezone
()
->
bool
{
env_is_truthy
(
"DYN_LOG_USE_LOCAL_TZ"
)
}
#[cfg(test)]
#[cfg(test)]
mod
tests
{
mod
tests
{
use
super
::
*
;
use
super
::
*
;
...
...
lib/runtime/src/logging.rs
View file @
5b682f48
...
@@ -23,6 +23,8 @@
...
@@ -23,6 +23,8 @@
//! Logging can take two forms: `READABLE` or `JSONL`. The default is `READABLE`. `JSONL`
//! Logging can take two forms: `READABLE` or `JSONL`. The default is `READABLE`. `JSONL`
//! can be enabled by setting the `DYN_LOGGING_JSONL` environment variable to `1`.
//! can be enabled by setting the `DYN_LOGGING_JSONL` environment variable to `1`.
//!
//!
//! To use local timezone for logging timestamps, set the `DYN_LOG_USE_LOCAL_TZ` environment variable to `1`.
//!
//! Filters can be configured using the `DYN_LOG` environment variable or by setting the `filters`
//! Filters can be configured using the `DYN_LOG` environment variable or by setting the `filters`
//! key in the TOML configuration file. Filters are comma-separated key-value pairs where the key
//! key in the TOML configuration file. Filters are comma-separated key-value pairs where the key
//! is the crate or module name and the value is the log level. The default log level is `info`.
//! is the crate or module name and the value is the log level. The default log level is `info`.
...
@@ -45,6 +47,10 @@ use figment::{
...
@@ -45,6 +47,10 @@ use figment::{
};
};
use
serde
::{
Deserialize
,
Serialize
};
use
serde
::{
Deserialize
,
Serialize
};
use
tracing
::{
Event
,
Subscriber
};
use
tracing
::{
Event
,
Subscriber
};
use
tracing_subscriber
::
fmt
::
time
::
FormatTime
;
use
tracing_subscriber
::
fmt
::
time
::
LocalTime
;
use
tracing_subscriber
::
fmt
::
time
::
SystemTime
;
use
tracing_subscriber
::
fmt
::
time
::
UtcTime
;
use
tracing_subscriber
::
fmt
::{
format
::
Writer
,
FormattedFields
};
use
tracing_subscriber
::
fmt
::{
format
::
Writer
,
FormattedFields
};
use
tracing_subscriber
::
fmt
::{
FmtContext
,
FormatFields
};
use
tracing_subscriber
::
fmt
::{
FmtContext
,
FormatFields
};
use
tracing_subscriber
::
prelude
::
*
;
use
tracing_subscriber
::
prelude
::
*
;
...
@@ -112,15 +118,14 @@ pub fn init() {
...
@@ -112,15 +118,14 @@ pub fn init() {
if
crate
::
config
::
jsonl_logging_enabled
()
{
if
crate
::
config
::
jsonl_logging_enabled
()
{
let
l
=
fmt
::
layer
()
let
l
=
fmt
::
layer
()
.with_ansi
(
false
)
// ansi terminal escapes and colors always disabled
.with_ansi
(
false
)
// ansi terminal escapes and colors always disabled
.event_format
(
CustomJsonFormatter
)
.event_format
(
CustomJsonFormatter
::
new
()
)
.with_writer
(
std
::
io
::
stderr
)
.with_writer
(
std
::
io
::
stderr
)
.with_filter
(
filter_layer
);
.with_filter
(
filter_layer
);
//let l = fmt::layer().json().with_filter(filter_layer);
tracing_subscriber
::
registry
()
.with
(
l
)
.init
();
tracing_subscriber
::
registry
()
.with
(
l
)
.init
();
}
else
{
}
else
{
let
l
=
fmt
::
layer
()
let
l
=
fmt
::
layer
()
.with_ansi
(
!
crate
::
config
::
disable_ansi_logging
())
.with_ansi
(
!
crate
::
config
::
disable_ansi_logging
())
.event_format
(
fmt
::
format
()
.compact
())
.event_format
(
fmt
::
format
()
.compact
()
.with_timer
(
TimeFormatter
::
new
())
)
.with_writer
(
std
::
io
::
stderr
)
.with_writer
(
std
::
io
::
stderr
)
.with_filter
(
filter_layer
);
.with_filter
(
filter_layer
);
tracing_subscriber
::
registry
()
.with
(
l
)
.init
();
tracing_subscriber
::
registry
()
.with
(
l
)
.init
();
...
@@ -174,8 +179,47 @@ struct JsonLog<'a> {
...
@@ -174,8 +179,47 @@ struct JsonLog<'a> {
fields
:
BTreeMap
<
String
,
serde_json
::
Value
>
,
fields
:
BTreeMap
<
String
,
serde_json
::
Value
>
,
}
}
/// Some teams (NVCF) require specific JSON style
struct
TimeFormatter
{
struct
CustomJsonFormatter
;
use_local_tz
:
bool
,
}
impl
TimeFormatter
{
fn
new
()
->
Self
{
Self
{
use_local_tz
:
crate
::
config
::
use_local_timezone
(),
}
}
fn
format_now
(
&
self
)
->
String
{
if
self
.use_local_tz
{
chrono
::
Local
::
now
()
.format
(
"%Y-%m-%dT%H:%M:%S%.3f%:z"
)
.to_string
()
}
else
{
chrono
::
Utc
::
now
()
.format
(
"%Y-%m-%dT%H:%M:%S%.3fZ"
)
.to_string
()
}
}
}
impl
FormatTime
for
TimeFormatter
{
fn
format_time
(
&
self
,
w
:
&
mut
fmt
::
format
::
Writer
<
'_
>
)
->
std
::
fmt
::
Result
{
write!
(
w
,
"{}"
,
self
.format_now
())
}
}
struct
CustomJsonFormatter
{
time_formatter
:
TimeFormatter
,
}
impl
CustomJsonFormatter
{
fn
new
()
->
Self
{
Self
{
time_formatter
:
TimeFormatter
::
new
(),
}
}
}
impl
<
S
,
N
>
tracing_subscriber
::
fmt
::
FormatEvent
<
S
,
N
>
for
CustomJsonFormatter
impl
<
S
,
N
>
tracing_subscriber
::
fmt
::
FormatEvent
<
S
,
N
>
for
CustomJsonFormatter
where
where
...
@@ -201,10 +245,6 @@ where
...
@@ -201,10 +245,6 @@ where
.or_else
(||
ctx
.lookup_current
());
.or_else
(||
ctx
.lookup_current
());
if
let
Some
(
span
)
=
current_span
{
if
let
Some
(
span
)
=
current_span
{
let
ext
=
span
.extensions
();
let
ext
=
span
.extensions
();
// This won't work is there's a space in the string, and loses the types making every
// span attribute a string.
// I think the correct way is to make a Layer.
// tracing_subscriber makes everything far more complicated than necessary.
let
data
=
ext
.get
::
<
FormattedFields
<
N
>>
()
.unwrap
();
let
data
=
ext
.get
::
<
FormattedFields
<
N
>>
()
.unwrap
();
let
span_fields
:
Vec
<
(
&
str
,
&
str
)
>
=
data
let
span_fields
:
Vec
<
(
&
str
,
&
str
)
>
=
data
.fields
.fields
...
@@ -226,7 +266,7 @@ where
...
@@ -226,7 +266,7 @@ where
let
metadata
=
event
.metadata
();
let
metadata
=
event
.metadata
();
let
log
=
JsonLog
{
let
log
=
JsonLog
{
level
:
metadata
.level
()
.to_string
(),
level
:
metadata
.level
()
.to_string
(),
time
:
format!
(
"{}"
,
chrono
::
Local
::
now
()
.format
(
"%m-%d %H:%M:%S.%3f"
)
),
time
:
self
.time_formatter
.format_now
(
),
file_path
:
if
cfg!
(
debug_assertions
)
{
file_path
:
if
cfg!
(
debug_assertions
)
{
metadata
.file
()
metadata
.file
()
}
else
{
}
else
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment