Skip to content

Commit 9879f4e

Browse files
authored
Merge pull request #224 from DiamondLightSource/logging
2 parents dba6908 + 41ae86d commit 9879f4e

File tree

22 files changed

+579
-27
lines changed

22 files changed

+579
-27
lines changed

.vscode/launch.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,14 @@
3939
"request": "launch",
4040
"justMyCode": false,
4141
"module": "fastcs.demo",
42-
"args": ["run", "${workspaceFolder:FastCS}/src/fastcs/demo/controller.yaml"],
42+
"args": [
43+
"run",
44+
"${workspaceFolder:FastCS}/src/fastcs/demo/controller.yaml",
45+
"--log-level",
46+
"TRACE",
47+
// "--graylog-endpoint",
48+
// "graylog-log-target.diamond.ac.uk:12201",
49+
],
4350
"console": "integratedTerminal",
4451
}
4552
]

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ dependencies = [
1919
"pydantic",
2020
"ruamel.yaml",
2121
"IPython",
22+
"loguru~=0.7",
23+
"pygelf",
2224
]
2325
dynamic = ["version"]
2426
license.file = "LICENSE"

src/fastcs/attribute_io.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
from fastcs.attribute_io_ref import AttributeIORef, AttributeIORefT
44
from fastcs.attributes import AttrR, AttrRW
55
from fastcs.datatypes import T
6+
from fastcs.tracer import Tracer
67

78

8-
class AttributeIO(Generic[T, AttributeIORefT]):
9+
class AttributeIO(Generic[T, AttributeIORefT], Tracer):
910
ref_type = AttributeIORef
1011

1112
def __init_subclass__(cls) -> None:

src/fastcs/attributes.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,21 @@
44
from collections.abc import Callable
55
from typing import Generic
66

7-
from .attribute_io_ref import AttributeIORefT
8-
from .datatypes import ATTRIBUTE_TYPES, AttrSetCallback, AttrUpdateCallback, DataType, T
7+
from fastcs.attribute_io_ref import AttributeIORefT
8+
from fastcs.datatypes import (
9+
ATTRIBUTE_TYPES,
10+
AttrSetCallback,
11+
AttrUpdateCallback,
12+
DataType,
13+
T,
14+
)
15+
from fastcs.tracer import Tracer
916

1017
ONCE = float("inf")
1118
"""Special value to indicate that an attribute should be updated once on start up."""
1219

1320

14-
class Attribute(Generic[T, AttributeIORefT]):
21+
class Attribute(Generic[T, AttributeIORefT], Tracer):
1522
"""Base FastCS attribute.
1623
1724
Instances of this class added to a ``Controller`` will be used by the FastCS class.
@@ -24,6 +31,8 @@ def __init__(
2431
group: str | None = None,
2532
description: str | None = None,
2633
) -> None:
34+
super().__init__()
35+
2736
assert issubclass(datatype.dtype, ATTRIBUTE_TYPES), (
2837
f"Attr type must be one of {ATTRIBUTE_TYPES}, "
2938
"received type {datatype.dtype}"
@@ -73,6 +82,9 @@ def update_datatype(self, datatype: DataType[T]) -> None:
7382
for callback in self._update_datatype_callbacks:
7483
callback(datatype)
7584

85+
def __repr__(self):
86+
return f"{self.__class__.__name__}({self._datatype})"
87+
7688

7789
class AttrR(Attribute[T, AttributeIORefT]):
7890
"""A read-only ``Attribute``."""
@@ -101,6 +113,8 @@ def get(self) -> T:
101113
return self._value
102114

103115
async def set(self, value: T) -> None:
116+
self.log_event("Attribute set", attribute=self, value=value)
117+
104118
self._value = self._datatype.validate(value)
105119

106120
if self._on_set_callbacks is not None:

src/fastcs/connections/ip_connection.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import asyncio
22
from dataclasses import dataclass
33

4+
from fastcs.tracer import Tracer
5+
46

57
class DisconnectedError(Exception):
68
"""Raised if the ip connection is disconnected."""
@@ -44,10 +46,11 @@ async def close(self):
4446
await self.writer.wait_closed()
4547

4648

47-
class IPConnection:
49+
class IPConnection(Tracer):
4850
"""For connecting to an ip using a `StreamConnection`."""
4951

5052
def __init__(self):
53+
super().__init__()
5154
self.__connection = None
5255

5356
@property
@@ -61,14 +64,20 @@ async def connect(self, settings: IPConnectionSettings):
6164
reader, writer = await asyncio.open_connection(settings.ip, settings.port)
6265
self.__connection = StreamConnection(reader, writer)
6366

64-
async def send_command(self, message) -> None:
67+
async def send_command(self, message: str) -> None:
6568
async with self._connection as connection:
6669
await connection.send_message(message)
6770

68-
async def send_query(self, message) -> str:
71+
async def send_query(self, message: str) -> str:
6972
async with self._connection as connection:
7073
await connection.send_message(message)
71-
return await connection.receive_response()
74+
response = await connection.receive_response()
75+
self.log_event(
76+
"Received query response",
77+
query=message.strip(),
78+
response=response.strip(),
79+
)
80+
return response
7281

7382
async def close(self):
7483
async with self._connection as connection:

src/fastcs/controller.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@
99
from fastcs.attribute_io_ref import AttributeIORefT
1010
from fastcs.attributes import Attribute, AttrR, AttrRW, AttrW
1111
from fastcs.datatypes import T
12+
from fastcs.tracer import Tracer
1213

1314

14-
class BaseController:
15+
class BaseController(Tracer):
1516
"""Base class for controller."""
1617

1718
#: Attributes passed from the device at runtime.
@@ -25,6 +26,8 @@ def __init__(
2526
description: str | None = None,
2627
ios: Sequence[AttributeIO[T, AttributeIORefT]] | None = None,
2728
) -> None:
29+
super().__init__()
30+
2831
if (
2932
description is not None
3033
): # Use the argument over the one class defined description.
@@ -182,6 +185,11 @@ def register_sub_controller(self, name: str, sub_controller: Controller):
182185
def get_sub_controllers(self) -> dict[str, Controller]:
183186
return self.__sub_controller_tree
184187

188+
def __repr__(self):
189+
return f"""\
190+
{type(self).__name__}({self.path}, {list(self.__sub_controller_tree.keys())})\
191+
"""
192+
185193

186194
class Controller(BaseController):
187195
"""Top-level controller for a device.

src/fastcs/controller_api.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,8 @@ def walk_api(self) -> Iterator["ControllerAPI"]:
2929
yield self
3030
for api in self.sub_apis.values():
3131
yield from api.walk_api()
32+
33+
def __repr__(self):
34+
return f"""\
35+
ControllerAPI(path={self.path}, sub_apis=[{", ".join(self.sub_apis.keys())}])\
36+
"""

src/fastcs/cs_methods.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from typing import Any, Generic, TypeVar
66

77
from fastcs.controller import BaseController
8+
from fastcs.tracer import Tracer
89

910
from .exceptions import FastCSError
1011

@@ -31,10 +32,12 @@
3132
)
3233

3334

34-
class Method(Generic[Controller_T]):
35+
class Method(Generic[Controller_T], Tracer):
3536
"""Generic base class for all FastCS Controller methods."""
3637

3738
def __init__(self, fn: MethodCallback, *, group: str | None = None) -> None:
39+
super().__init__()
40+
3841
self._docstring = getdoc(fn)
3942

4043
sig = signature(fn, eval_str=True)

src/fastcs/demo/controller.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ transport:
1010
port: 8083
1111
log_level: info
1212
- ca_ioc:
13-
pv_prefix: DEMO
13+
pv_prefix: GARYDEMO
1414
gui:
1515
title: Temperature Controller Demo
1616
output_path: ./demo.bob

src/fastcs/demo/controllers.py

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ class TemperatureControllerAttributeIORef(AttributeIORef):
3333
name: str
3434
update_period: float | None = 0.2
3535

36+
def __post_init__(self):
37+
# Call __init__ of non-dataclass parent
38+
super().__init__()
39+
3640

3741
class TemperatureControllerAttributeIO(
3842
AttributeIO[NumberT, TemperatureControllerAttributeIORef]
@@ -44,17 +48,22 @@ def __init__(self, connection: IPConnection, suffix: str):
4448
async def send(
4549
self, attr: AttrW[NumberT, TemperatureControllerAttributeIORef], value: NumberT
4650
) -> None:
47-
await self._connection.send_command(
48-
f"{attr.io_ref.name}{self.suffix}={attr.dtype(value)}\r\n"
49-
)
51+
command = f"{attr.io_ref.name}{self.suffix}={attr.dtype(value)}"
52+
await self._connection.send_command(f"{command}\r\n")
53+
self.log_event("Send command for attribute", topic=attr, command=command)
5054

5155
async def update(
5256
self, attr: AttrR[NumberT, TemperatureControllerAttributeIORef]
5357
) -> None:
54-
response = await self._connection.send_query(
55-
f"{attr.io_ref.name}{self.suffix}?\r\n"
56-
)
58+
query = f"{attr.io_ref.name}{self.suffix}?"
59+
response = await self._connection.send_query(f"{query}?\r\n")
5760
response = response.strip("\r\n")
61+
self.log_event(
62+
"Query for attribute",
63+
topic=attr,
64+
query=query,
65+
response=response,
66+
)
5867

5968
await attr.set(attr.dtype(response))
6069

@@ -93,10 +102,17 @@ async def close(self) -> None:
93102

94103
@scan(0.1)
95104
async def update_voltages(self):
105+
query = "V?"
96106
voltages = json.loads(
97-
(await self.connection.send_query("V?\r\n")).strip("\r\n")
107+
(await self.connection.send_query(f"{query}\r\n")).strip("\r\n")
98108
)
99109
for index, controller in enumerate(self._ramp_controllers):
110+
self.log_event(
111+
"Update voltages",
112+
topic=controller.voltage,
113+
query=query,
114+
response=voltages,
115+
)
100116
await controller.voltage.set(float(voltages[index]))
101117

102118

0 commit comments

Comments
 (0)