Skip to content

Commit

Permalink
Add logfire.work_dir resource attribute (#532)
Browse files Browse the repository at this point in the history
Co-authored-by: Alex Hall <[email protected]>
  • Loading branch information
Kludex and alexmojaki authored Oct 30, 2024
1 parent e954e2a commit 5480347
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 10 deletions.
2 changes: 1 addition & 1 deletion docs/guides/advanced/link-to-code-source.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ logfire.configure(
code_source=logfire.CodeSource(
repository='https://github.com/pydantic/logfire', #(1)!
revision='<hash of commit used on release>', #(2)!
root_path='.', #(3)!
root_path='/root/path', #(3)!
)
)
```
Expand Down
17 changes: 13 additions & 4 deletions logfire/_internal/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
DEFAULT_FALLBACK_FILE_NAME,
OTLP_MAX_BODY_SIZE,
RESOURCE_ATTRIBUTES_CODE_ROOT_PATH,
RESOURCE_ATTRIBUTES_CODE_WORK_DIR,
RESOURCE_ATTRIBUTES_VCS_REPOSITORY_REF_REVISION,
RESOURCE_ATTRIBUTES_VCS_REPOSITORY_URL,
LevelName,
Expand Down Expand Up @@ -207,12 +208,18 @@ class CodeSource:
revision: str
"""The git revision of the code e.g. branch name, commit hash, tag name etc."""

root_path: str
root_path: str = ''
"""The root path for the source code in the repository.
If you run the code from the directory corresponding to the root of the repository, you can leave this blank.
Example:
If the `code.filename` is `/path/to/project/src/logfire/main.py` and the `root_path` is `src/`, the URL
for the source code will be `src/path/to/project/src/logfire/main.py`.
Suppose that your repository contains `a/b/c/main.py`, the folder `a/b/` is copied
into the `/docker/root/` folder of your docker container, and within the container
the command `python ./b/c/main.py` is run from within the `/docker/root/a/` directory.
Then `code.filepath` will be `b/c/main.py` for spans created in that file, and the
`root_path` should be set to `a` so that the final link is `a/b/c/main.py`.
"""


Expand Down Expand Up @@ -672,11 +679,13 @@ def _initialize(self) -> None:
if self.code_source:
otel_resource_attributes.update(
{
RESOURCE_ATTRIBUTES_CODE_ROOT_PATH: self.code_source.root_path,
RESOURCE_ATTRIBUTES_CODE_WORK_DIR: os.getcwd(),
RESOURCE_ATTRIBUTES_VCS_REPOSITORY_URL: self.code_source.repository,
RESOURCE_ATTRIBUTES_VCS_REPOSITORY_REF_REVISION: self.code_source.revision,
}
)
if self.code_source.root_path:
otel_resource_attributes[RESOURCE_ATTRIBUTES_CODE_ROOT_PATH] = self.code_source.root_path
if self.service_version:
otel_resource_attributes[ResourceAttributes.SERVICE_VERSION] = self.service_version
otel_resource_attributes_from_env = os.getenv(OTEL_RESOURCE_ATTRIBUTES)
Expand Down
3 changes: 3 additions & 0 deletions logfire/_internal/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,9 @@ def log_level_attributes(level: LevelName | int) -> dict[str, otel_types.Attribu
RESOURCE_ATTRIBUTES_CODE_ROOT_PATH = 'logfire.code.root_path'
"""The root path of the current repository."""

RESOURCE_ATTRIBUTES_CODE_WORK_DIR = 'logfire.code.work_dir'
"""The working directory of the application."""

OTLP_MAX_INT_SIZE = 2**63 - 1
"""OTLP only supports signed 64-bit integers, larger integers get sent as strings."""

Expand Down
55 changes: 50 additions & 5 deletions tests/test_configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -837,11 +837,7 @@ def test_config_serializable():
console=logfire.ConsoleOptions(verbose=True),
sampling=logfire.SamplingOptions(),
scrubbing=logfire.ScrubbingOptions(),
code_source=logfire.CodeSource(
repository='https://github.com/pydantic/logfire',
revision='main',
root_path='.',
),
code_source=logfire.CodeSource(repository='https://github.com/pydantic/logfire', revision='main'),
)

for field in dataclasses.fields(GLOBAL_CONFIG):
Expand Down Expand Up @@ -1647,6 +1643,55 @@ def test_code_source(config_kwargs: dict[str, Any], exporter: TestExporter):
'service.name': 'unknown_service',
'process.pid': 1234,
'logfire.code.root_path': 'logfire',
'logfire.code.work_dir': os.getcwd(),
'vcs.repository.url.full': 'https://github.com/pydantic/logfire',
'vcs.repository.ref.revision': 'main',
'service.version': '1.2.3',
}
},
}
]
)


def test_code_source_without_root_path(config_kwargs: dict[str, Any], exporter: TestExporter):
configure(
**config_kwargs,
service_version='1.2.3',
code_source=CodeSource(
repository='https://github.com/pydantic/logfire',
revision='main',
),
)

logfire.info('test1')

assert exporter.exported_spans_as_dict(include_resources=True) == snapshot(
[
{
'name': 'test1',
'context': {'trace_id': 1, 'span_id': 1, 'is_remote': False},
'parent': None,
'start_time': 1000000000,
'end_time': 1000000000,
'attributes': {
'logfire.span_type': 'log',
'logfire.level_num': 9,
'logfire.msg_template': 'test1',
'logfire.msg': 'test1',
'code.filepath': 'test_configure.py',
'code.function': 'test_code_source_without_root_path',
'code.lineno': 123,
},
'resource': {
'attributes': {
'service.instance.id': '00000000000000000000000000000000',
'telemetry.sdk.language': 'python',
'telemetry.sdk.name': 'opentelemetry',
'telemetry.sdk.version': '0.0.0',
'service.name': 'unknown_service',
'process.pid': 1234,
'logfire.code.work_dir': os.getcwd(),
'vcs.repository.url.full': 'https://github.com/pydantic/logfire',
'vcs.repository.ref.revision': 'main',
'service.version': '1.2.3',
Expand Down

0 comments on commit 5480347

Please sign in to comment.