Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
bba824e
chore: update Ruff's project lint config
pvital Apr 2, 2026
49b6a49
style: fix error [E117] - Over-indented
pvital Apr 2, 2026
f5f05e9
style: fix error [UP031] - Use format specifiers instead of percent f…
pvital Apr 2, 2026
a820ce9
style: fix error [UP032] - Use f-string instead of `format` call.
pvital Apr 2, 2026
520a69d
style: fix error [F401] - {package} imported but unused.
pvital Apr 2, 2026
75d649f
style: fix error [E302] - Expected 2 blank lines, found 1.
pvital Apr 3, 2026
86aa08c
style: fix error [CPY001] - Missing copyright notice at top of file.
pvital Apr 3, 2026
4c80d51
style: fix error [E303] - Too many blank lines (2).
pvital Apr 3, 2026
147675d
style: fix error [E714] - Test for object identity should be `is not`.
pvital Apr 3, 2026
f602ecd
style: fix error [E222] - Multiple spaces after operator.
pvital Apr 3, 2026
1bb2832
style: fix error [FLY002] - Consider `f"{start}-{end}"` instead of st…
pvital Apr 3, 2026
42009d9
style: fix error [E266] - Too many leading `#` before block comment.
pvital Apr 4, 2026
d895a3b
style: fix error [SIM300] - Yoda condition detected.
pvital Apr 4, 2026
a1a47b2
style: fix error [SIM118] - Use `key in dict` instead of `key in dict…
pvital Apr 4, 2026
7a9ce60
style: fix error [SIM105] - Use `contextlib.suppress(Exception)` inst…
pvital Apr 5, 2026
08083c5
style: fix error [SIM910] - Use `headers.get(<index>)` instead of `he…
pvital Apr 6, 2026
53bc26d
style: fix error [SIM117] - Use a single `with` statement with multip…
pvital Apr 7, 2026
84ace19
style: fix error [SIM102] - Use a single `if` statement instead of ne…
pvital Apr 7, 2026
c389f78
style: fix error [SIM103] - Return the condition `bool(<CONDITION>)` …
pvital Apr 7, 2026
2ae4905
style: fix error [SIM108] - Use ternary operator instead of `if`-`els…
pvital Apr 7, 2026
3b534e7
style: fix error [SIM211] - Use `not ...` instead of `False if ... el…
pvital Apr 7, 2026
3516d15
fix: SonarQube failed conditions on new code.
pvital Apr 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.7.0
rev: v0.15.9
hooks:
# Run the linter.
- id: ruff
- id: ruff-check
args: [ --fix ]
# Run the formatter.
- id: ruff-format
types_or: [python, markdown]
30 changes: 30 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ dev = [
"pytest-mock",
"pre-commit>=3.0.0",
"ruff",
"gunicorn",
]

[project.urls]
Expand Down Expand Up @@ -94,3 +95,32 @@ exclude_also = [
"except Exception:",
"except Exception as exc:",
]

[tool.ruff]
# https://docs.astral.sh/ruff/configuration/
target-version = "py39"
# In addition to the standard set of exclusions, omit all tests, plus a specific file.
extend-exclude = [".bob", "bin", ".github", ".circleci", ".tekton"]
preview = true
output-format = "concise"

[tool.ruff.lint]
# https://docs.astral.sh/ruff/rules/
select = [
"E", # pycodestyle
"F", # Pyflakes
"I", # isort
"CPY", # flake8-copyright
"SIM", # flake8-simplify
"FLY", # flynt (static-join-to-f-string)
"UP031", # printf-string-formatting
"UP032", # f-string
]
ignore = ["E501", "I001"]

[tool.ruff.lint.flake8-copyright]
notice-rgx = "(?i)#\\s?(\\(c\\)\\s+)?Copyright\\s+IBM Corp\\.\\s+(\\d{4}((-|,\\s)\\d{4})?)"
min-file-size = 1024

# [tool.ruff.format]
# preview = true
48 changes: 30 additions & 18 deletions src/instana/agent/aws_eks_fargate.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@
The Instana agent (for AWS EKS Fargate) that manages
monitoring state and reporting that data.
"""
import os
import time
from instana.options import EKSFargateOptions

from instana.agent.base import BaseAgent
from instana.collector.aws_eks_fargate import EKSFargateCollector
from instana.collector.helpers.eks.process import get_pod_name
from instana.log import logger
from instana.options import EKSFargateOptions
from instana.util import to_json
from instana.agent.base import BaseAgent
from instana.version import VERSION


class EKSFargateAgent(BaseAgent):
""" In-process agent for AWS Fargate """
"""In-process agent for AWS Fargate"""

def __init__(self):
super(EKSFargateAgent, self).__init__()

Expand All @@ -29,15 +29,20 @@ def __init__(self):
# Update log level (if INSTANA_LOG_LEVEL was set)
self.update_log_level()

logger.info("Stan is on the EKS Pod on AWS Fargate scene. Starting Instana instrumentation version: %s", VERSION)
logger.info(
"Stan is on the EKS Pod on AWS Fargate scene. Starting Instana instrumentation version: %s",
VERSION,
)

if self._validate_options():
self._can_send = True
self.collector = EKSFargateCollector(self)
self.collector.start()
else:
logger.warning("Required INSTANA_AGENT_KEY and/or INSTANA_ENDPOINT_URL environment variables not set. "
"We will not be able to monitor this Pod.")
logger.warning(
"Required INSTANA_AGENT_KEY and/or INSTANA_ENDPOINT_URL environment variables not set. "
"We will not be able to monitor this Pod."
)

def can_send(self):
"""
Expand All @@ -52,7 +57,7 @@ def get_from_structure(self):
@return: dict()
"""

return {'hl': True, 'cp': 'k8s', 'e': self.podname}
return {"hl": True, "cp": "k8s", "e": self.podname}

def report_data_payload(self, payload):
"""
Expand All @@ -67,15 +72,20 @@ def report_data_payload(self, payload):
self.report_headers["X-Instana-Host"] = self.podname
self.report_headers["X-Instana-Key"] = self.options.agent_key

response = self.client.post(self.__data_bundle_url(),
data=to_json(payload),
headers=self.report_headers,
timeout=self.options.timeout,
verify=self.options.ssl_verify,
proxies=self.options.endpoint_proxy)
response = self.client.post(
self.__data_bundle_url(),
data=to_json(payload),
headers=self.report_headers,
timeout=self.options.timeout,
verify=self.options.ssl_verify,
proxies=self.options.endpoint_proxy,
)

if not 200 <= response.status_code < 300:
logger.info("report_data_payload: Instana responded with status code %s", response.status_code)
logger.info(
"report_data_payload: Instana responded with status code %s",
response.status_code,
)
except Exception as exc:
logger.debug("report_data_payload: connection error (%s)", type(exc))
return response
Expand All @@ -84,10 +94,12 @@ def _validate_options(self):
"""
Validate that the options used by this Agent are valid. e.g. can we report data?
"""
return self.options.endpoint_url is not None and self.options.agent_key is not None
return (
self.options.endpoint_url is not None and self.options.agent_key is not None
)

def __data_bundle_url(self):
"""
URL for posting metrics to the host agent. Only valid when announced.
"""
return "%s/bundle" % self.options.endpoint_url
return f"{self.options.endpoint_url}/bundle"
48 changes: 31 additions & 17 deletions src/instana/agent/aws_fargate.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,19 @@
The Instana agent (for AWS Fargate) that manages
monitoring state and reporting that data.
"""
import time
from instana.options import AWSFargateOptions

from instana.collector.aws_fargate import AWSFargateCollector
from instana.options import AWSFargateOptions

from ..log import logger
from ..util import to_json
from .base import BaseAgent
from ..version import VERSION
from .base import BaseAgent


class AWSFargateAgent(BaseAgent):
""" In-process agent for AWS Fargate """
"""In-process agent for AWS Fargate"""

def __init__(self):
super(AWSFargateAgent, self).__init__()

Expand All @@ -27,15 +29,20 @@ def __init__(self):
# Update log level (if INSTANA_LOG_LEVEL was set)
self.update_log_level()

logger.info("Stan is on the AWS Fargate scene. Starting Instana instrumentation version: %s", VERSION)
logger.info(
"Stan is on the AWS Fargate scene. Starting Instana instrumentation version: %s",
VERSION,
)

if self._validate_options():
self._can_send = True
self.collector = AWSFargateCollector(self)
self.collector.start()
else:
logger.warning("Required INSTANA_AGENT_KEY and/or INSTANA_ENDPOINT_URL environment variables not set. "
"We will not be able monitor this AWS Fargate cluster.")
logger.warning(
"Required INSTANA_AGENT_KEY and/or INSTANA_ENDPOINT_URL environment variables not set. "
"We will not be able monitor this AWS Fargate cluster."
)

def can_send(self):
"""
Expand All @@ -49,7 +56,7 @@ def get_from_structure(self):
Retrieves the From data that is reported alongside monitoring data.
@return: dict()
"""
return {'hl': True, 'cp': 'aws', 'e': self.collector.get_fq_arn()}
return {"hl": True, "cp": "aws", "e": self.collector.get_fq_arn()}

def report_data_payload(self, payload):
"""
Expand All @@ -64,15 +71,20 @@ def report_data_payload(self, payload):
self.report_headers["X-Instana-Host"] = self.collector.get_fq_arn()
self.report_headers["X-Instana-Key"] = self.options.agent_key

response = self.client.post(self.__data_bundle_url(),
data=to_json(payload),
headers=self.report_headers,
timeout=self.options.timeout,
verify=self.options.ssl_verify,
proxies=self.options.endpoint_proxy)
response = self.client.post(
self.__data_bundle_url(),
data=to_json(payload),
headers=self.report_headers,
timeout=self.options.timeout,
verify=self.options.ssl_verify,
proxies=self.options.endpoint_proxy,
)

if not 200 <= response.status_code < 300:
logger.info("report_data_payload: Instana responded with status code %s", response.status_code)
logger.info(
"report_data_payload: Instana responded with status code %s",
response.status_code,
)
except Exception as exc:
logger.debug("report_data_payload: connection error (%s)", type(exc))
return response
Expand All @@ -81,10 +93,12 @@ def _validate_options(self):
"""
Validate that the options used by this Agent are valid. e.g. can we report data?
"""
return self.options.endpoint_url is not None and self.options.agent_key is not None
return (
self.options.endpoint_url is not None and self.options.agent_key is not None
)

def __data_bundle_url(self):
"""
URL for posting metrics to the host agent. Only valid when announced.
"""
return "%s/bundle" % self.options.endpoint_url
return f"{self.options.endpoint_url}/bundle"
47 changes: 29 additions & 18 deletions src/instana/agent/google_cloud_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
The Instana agent (for GCR) that manages
monitoring state and reporting that data.
"""
import time

from instana.options import GCROptions
from instana.collector.google_cloud_run import GCRCollector
from instana.log import logger
Expand All @@ -15,7 +15,7 @@


class GCRAgent(BaseAgent):
""" In-process agent for Google Cloud Run """
"""In-process agent for Google Cloud Run"""

def __init__(self, service, configuration, revision):
super(GCRAgent, self).__init__()
Expand All @@ -28,15 +28,20 @@ def __init__(self, service, configuration, revision):
# Update log level (if INSTANA_LOG_LEVEL was set)
self.update_log_level()

logger.info("Stan is on the AWS Fargate scene. Starting Instana instrumentation version: %s", VERSION)
logger.info(
"Stan is on the AWS Fargate scene. Starting Instana instrumentation version: %s",
VERSION,
)

if self._validate_options():
self._can_send = True
self.collector = GCRCollector(self, service, configuration, revision)
self.collector.start()
else:
logger.warning("Required INSTANA_AGENT_KEY and/or INSTANA_ENDPOINT_URL environment variables not set. "
"We will not be able monitor this GCR cluster.")
logger.warning(
"Required INSTANA_AGENT_KEY and/or INSTANA_ENDPOINT_URL environment variables not set. "
"We will not be able monitor this GCR cluster."
)

def can_send(self):
"""
Expand All @@ -50,7 +55,7 @@ def get_from_structure(self):
Retrieves the From data that is reported alongside monitoring data.
@return: dict()
"""
return {'hl': True, 'cp': 'gcp', 'e': self.collector.get_instance_id()}
return {"hl": True, "cp": "gcp", "e": self.collector.get_instance_id()}

def report_data_payload(self, payload):
"""
Expand All @@ -62,20 +67,24 @@ def report_data_payload(self, payload):
# Prepare request headers
self.report_headers = {
"Content-Type": "application/json",
"X-Instana-Host": "gcp:cloud-run:revision:{revision}".format(
revision=self.collector.revision),
"X-Instana-Key": self.options.agent_key
"X-Instana-Host": f"gcp:cloud-run:revision:{self.collector.revision}",
"X-Instana-Key": self.options.agent_key,
}

response = self.client.post(self.__data_bundle_url(),
data=to_json(payload),
headers=self.report_headers,
timeout=self.options.timeout,
verify=self.options.ssl_verify,
proxies=self.options.endpoint_proxy)
response = self.client.post(
self.__data_bundle_url(),
data=to_json(payload),
headers=self.report_headers,
timeout=self.options.timeout,
verify=self.options.ssl_verify,
proxies=self.options.endpoint_proxy,
)

if response.status_code >= 400:
logger.info("report_data_payload: Instana responded with status code %s", response.status_code)
logger.info(
"report_data_payload: Instana responded with status code %s",
response.status_code,
)
except Exception as exc:
logger.debug("report_data_payload: connection error (%s)", type(exc))
return response
Expand All @@ -84,10 +93,12 @@ def _validate_options(self):
"""
Validate that the options used by this Agent are valid. e.g. can we report data?
"""
return self.options.endpoint_url is not None and self.options.agent_key is not None
return (
self.options.endpoint_url is not None and self.options.agent_key is not None
)

def __data_bundle_url(self):
"""
URL for posting metrics to the host agent. Only valid when announced.
"""
return "{endpoint_url}/bundle".format(endpoint_url=self.options.endpoint_url)
return f"{self.options.endpoint_url}/bundle"
20 changes: 8 additions & 12 deletions src/instana/agent/host.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,7 @@ def can_send(self) -> bool:
logger.debug("Fork detected; Handling like a pro...")
self.handle_fork()

if self.machine.fsm.current in ["wait4init", "good2go"]:
return True

return False
return self.machine.fsm.current in ["wait4init", "good2go"]

def set_from(
self,
Expand Down Expand Up @@ -371,7 +368,7 @@ def filter_spans(self, spans: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
service_name = ""

# Set the service name
for span_value in span.data.keys():
for span_value in span.data:
if isinstance(span.data[span_value], dict):
service_name = span_value

Expand Down Expand Up @@ -413,13 +410,12 @@ def __is_endpoint_ignored(self, span_attributes: dict) -> bool:

# Check exclude rules
exclude_rules = filters.get("exclude", [])
if any(
matches_rule(rule.get("attributes", []), span_attributes)
for rule in exclude_rules
):
return True

return False
return bool(
any(
matches_rule(rule.get("attributes", []), span_attributes)
for rule in exclude_rules
)
)

def handle_agent_tasks(self, task: Dict[str, Any]) -> None:
"""
Expand Down
Loading
Loading