log-ctrl 0.0.1__tar.gz → 0.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {log_ctrl-0.0.1 → log_ctrl-0.0.4}/PKG-INFO +52 -48
- log_ctrl-0.0.4/README.md +188 -0
- {log_ctrl-0.0.1 → log_ctrl-0.0.4}/pyproject.toml +4 -2
- {log_ctrl-0.0.1 → log_ctrl-0.0.4}/src/log_ctrl.egg-info/PKG-INFO +52 -48
- log_ctrl-0.0.1/README.md +0 -184
- {log_ctrl-0.0.1 → log_ctrl-0.0.4}/LICENSE +0 -0
- {log_ctrl-0.0.1 → log_ctrl-0.0.4}/setup.cfg +0 -0
- {log_ctrl-0.0.1 → log_ctrl-0.0.4}/src/log_ctrl/__init__.py +0 -0
- {log_ctrl-0.0.1 → log_ctrl-0.0.4}/src/log_ctrl/log_ctrl.py +0 -0
- {log_ctrl-0.0.1 → log_ctrl-0.0.4}/src/log_ctrl/server_grpc/__init__.py +0 -0
- {log_ctrl-0.0.1 → log_ctrl-0.0.4}/src/log_ctrl/server_grpc/async_log_grpc_client.py +0 -0
- {log_ctrl-0.0.1 → log_ctrl-0.0.4}/src/log_ctrl/server_grpc/log_grpc_server.py +0 -0
- {log_ctrl-0.0.1 → log_ctrl-0.0.4}/src/log_ctrl/server_grpc/sync_log_grpc_client.py +0 -0
- {log_ctrl-0.0.1 → log_ctrl-0.0.4}/src/log_ctrl.egg-info/SOURCES.txt +0 -0
- {log_ctrl-0.0.1 → log_ctrl-0.0.4}/src/log_ctrl.egg-info/dependency_links.txt +0 -0
- {log_ctrl-0.0.1 → log_ctrl-0.0.4}/src/log_ctrl.egg-info/requires.txt +0 -0
- {log_ctrl-0.0.1 → log_ctrl-0.0.4}/src/log_ctrl.egg-info/top_level.txt +0 -0
- {log_ctrl-0.0.1 → log_ctrl-0.0.4}/tests/test_log_server.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
|
-
Name:
|
|
3
|
-
Version: 0.0.
|
|
2
|
+
Name: log-ctrl
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary: gRPC server and proxy for reading x_logger rotating log files by device class.
|
|
5
5
|
Author-email: Kengo NAKADA <kengo.nakada@email.com>
|
|
6
6
|
License: Apache License
|
|
@@ -230,16 +230,15 @@ Dynamic: license-file
|
|
|
230
230
|
|
|
231
231
|
# log_ctrl
|
|
232
232
|
|
|
233
|
-
[](https://github.com/ohara-lab-su/log_ctrl/blob/main/README.
|
|
234
|
-
[](https://github.com/ohara-lab-su/log_ctrl/blob/main/README.md)
|
|
233
|
+
[](https://github.com/ohara-lab-su/log_ctrl/blob/main/README.md)
|
|
234
|
+
[](https://github.com/ohara-lab-su/log_ctrl/blob/main/README.ja.md)
|
|
235
235
|
|
|
236
|
-
`log_ctrl`
|
|
237
|
-
|
|
238
|
-
を使ってネットワーク越しに参照するためのパッケージです。
|
|
236
|
+
`log_ctrl` is a package for accessing log files stored in a specified
|
|
237
|
+
log directory over a network using `grpc_frame`.
|
|
239
238
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
239
|
+
It does not add log retrieval RPCs to the DeviceServer or application
|
|
240
|
+
that writes the logs. `log_ctrl` runs as an independent, read-only gRPC
|
|
241
|
+
server that accesses existing log files.
|
|
243
242
|
|
|
244
243
|
``` text
|
|
245
244
|
application / DeviceServer
|
|
@@ -263,9 +262,9 @@ C:\opt\ese774\log
|
|
|
263
262
|
DeviceProxy("log", ...)
|
|
264
263
|
```
|
|
265
264
|
|
|
266
|
-
##
|
|
265
|
+
## Log names
|
|
267
266
|
|
|
268
|
-
`log_ctrl
|
|
267
|
+
In `log_ctrl`, the part before `.log` is called the `log_name`.
|
|
269
268
|
|
|
270
269
|
``` text
|
|
271
270
|
cobotta4_server.log
|
|
@@ -273,47 +272,52 @@ cobotta4_server.log
|
|
|
273
272
|
log_name
|
|
274
273
|
```
|
|
275
274
|
|
|
276
|
-
|
|
275
|
+
Rotated log files use the following format:
|
|
277
276
|
|
|
278
277
|
``` text
|
|
279
278
|
<log_name>.log.YYYY-MM-DD
|
|
280
279
|
```
|
|
281
280
|
|
|
282
|
-
`log_name`
|
|
283
|
-
|
|
284
|
-
|
|
281
|
+
The `log_name` does not need to match the DeviceServer name or device
|
|
282
|
+
class name. `log_ctrl` uses the `log_name` exactly as it appears in the
|
|
283
|
+
filename.
|
|
285
284
|
|
|
286
|
-
##
|
|
285
|
+
## Main features
|
|
287
286
|
|
|
288
|
-
- `log_names()
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
- `
|
|
293
|
-
|
|
294
|
-
- `
|
|
295
|
-
|
|
296
|
-
|
|
287
|
+
- `log_names()`: Get the list of `log_name` values from existing log
|
|
288
|
+
files.
|
|
289
|
+
- `dates(log_name)`: Get the list of rotation dates for the specified
|
|
290
|
+
`log_name`.
|
|
291
|
+
- `exists(log_name, date=None)`: Check whether the current log or a
|
|
292
|
+
log for a specified date exists.
|
|
293
|
+
- `tail(log_name, lines=100, date=None)`: Get the end of a log as a
|
|
294
|
+
string.
|
|
295
|
+
- `raw_files()`: List all files under the log directory as relative
|
|
296
|
+
paths.
|
|
297
|
+
- `read(log_name, date=None)`: Read a log file as `bytes`.
|
|
298
|
+
- `read_raw(relative_path)`: Read an arbitrary file confirmed by
|
|
299
|
+
`raw_files()` as `bytes`.
|
|
297
300
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
+
Large log files are transferred in chunks using `grpc_frame`
|
|
302
|
+
`StreamCall`. Client-side code does not need to handle the stream
|
|
303
|
+
directly; `read()` and `read_raw()` join the received chunks and return
|
|
304
|
+
them as `bytes`.
|
|
301
305
|
|
|
302
|
-
##
|
|
306
|
+
## Installation
|
|
303
307
|
|
|
304
|
-
`grpc_frame`
|
|
308
|
+
Install in an environment where `grpc_frame` is available.
|
|
305
309
|
|
|
306
310
|
``` bash
|
|
307
311
|
python -m pip install .
|
|
308
312
|
```
|
|
309
313
|
|
|
310
|
-
|
|
314
|
+
For development, use an editable install:
|
|
311
315
|
|
|
312
316
|
``` bash
|
|
313
317
|
python -m pip install -e .
|
|
314
318
|
```
|
|
315
319
|
|
|
316
|
-
## LogServer
|
|
320
|
+
## Starting LogServer
|
|
317
321
|
|
|
318
322
|
``` python
|
|
319
323
|
from log_ctrl.server_grpc import log_grpc_server
|
|
@@ -329,12 +333,12 @@ log_grpc_server(
|
|
|
329
333
|
)
|
|
330
334
|
```
|
|
331
335
|
|
|
332
|
-
`logger`
|
|
333
|
-
|
|
336
|
+
If `logger` is omitted, the standard `logging` module is used. To use an
|
|
337
|
+
existing logger, pass it with `logger=`.
|
|
334
338
|
|
|
335
|
-
##
|
|
339
|
+
## Client
|
|
336
340
|
|
|
337
|
-
`
|
|
341
|
+
Use `DeviceProxy` as the transparent `grpc_frame` client.
|
|
338
342
|
|
|
339
343
|
``` python
|
|
340
344
|
from log_ctrl.server_grpc import DeviceProxy
|
|
@@ -364,9 +368,10 @@ finally:
|
|
|
364
368
|
client.close()
|
|
365
369
|
```
|
|
366
370
|
|
|
367
|
-
`log_names()`
|
|
368
|
-
|
|
369
|
-
`exists(log_name)`
|
|
371
|
+
The names returned by `log_names()` are not limited to names for which a
|
|
372
|
+
current `<log_name>.log` file exists. A name is also included when only
|
|
373
|
+
rotated log files remain. Check `exists(log_name)` as needed before
|
|
374
|
+
reading the current log.
|
|
370
375
|
|
|
371
376
|
## API
|
|
372
377
|
|
|
@@ -388,20 +393,19 @@ client.read(log_name, date="2026-04-06")
|
|
|
388
393
|
client.read_raw("cobotta4_server.log.2026-04-06")
|
|
389
394
|
```
|
|
390
395
|
|
|
391
|
-
`read()`
|
|
392
|
-
|
|
393
|
-
decode します。
|
|
396
|
+
`read()` and `read_raw()` return `bytes`. To handle a log as text,
|
|
397
|
+
decode it on the client using the appropriate character encoding.
|
|
394
398
|
|
|
395
399
|
``` python
|
|
396
400
|
text = client.read(log_name).decode("utf-8")
|
|
397
401
|
```
|
|
398
402
|
|
|
399
|
-
`tail()`
|
|
400
|
-
|
|
403
|
+
`tail()` is decoded on the server using the configured `encoding` and
|
|
404
|
+
returns `str`.
|
|
401
405
|
|
|
402
|
-
##
|
|
406
|
+
## Documentation
|
|
403
407
|
|
|
404
|
-
Sphinx
|
|
408
|
+
Sphinx documentation is available under `docs/`.
|
|
405
409
|
|
|
406
410
|
- `docs/index.md`
|
|
407
411
|
- `docs/quickstart.md`
|
|
@@ -411,4 +415,4 @@ Sphinx 用文書は `docs/` にあります。
|
|
|
411
415
|
|
|
412
416
|
## License
|
|
413
417
|
|
|
414
|
-
`LICENSE
|
|
418
|
+
See `LICENSE`.
|
log_ctrl-0.0.4/README.md
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# log_ctrl
|
|
2
|
+
|
|
3
|
+
[](https://github.com/ohara-lab-su/log_ctrl/blob/main/README.md)
|
|
4
|
+
[](https://github.com/ohara-lab-su/log_ctrl/blob/main/README.ja.md)
|
|
5
|
+
|
|
6
|
+
`log_ctrl` is a package for accessing log files stored in a specified
|
|
7
|
+
log directory over a network using `grpc_frame`.
|
|
8
|
+
|
|
9
|
+
It does not add log retrieval RPCs to the DeviceServer or application
|
|
10
|
+
that writes the logs. `log_ctrl` runs as an independent, read-only gRPC
|
|
11
|
+
server that accesses existing log files.
|
|
12
|
+
|
|
13
|
+
``` text
|
|
14
|
+
application / DeviceServer
|
|
15
|
+
│
|
|
16
|
+
│ write
|
|
17
|
+
▼
|
|
18
|
+
C:\opt\ese774\log
|
|
19
|
+
├── cobotta4_server.log
|
|
20
|
+
├── cobotta4_server.log.2026-04-06
|
|
21
|
+
├── cobotta4_server2.log
|
|
22
|
+
└── cobotta4_server2.log.2026-06-16
|
|
23
|
+
▲
|
|
24
|
+
│ read only
|
|
25
|
+
│
|
|
26
|
+
LogCtrl
|
|
27
|
+
│
|
|
28
|
+
▼
|
|
29
|
+
log gRPC server
|
|
30
|
+
│
|
|
31
|
+
▼
|
|
32
|
+
DeviceProxy("log", ...)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Log names
|
|
36
|
+
|
|
37
|
+
In `log_ctrl`, the part before `.log` is called the `log_name`.
|
|
38
|
+
|
|
39
|
+
``` text
|
|
40
|
+
cobotta4_server.log
|
|
41
|
+
^^^^^^^^^^^^^^^
|
|
42
|
+
log_name
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Rotated log files use the following format:
|
|
46
|
+
|
|
47
|
+
``` text
|
|
48
|
+
<log_name>.log.YYYY-MM-DD
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The `log_name` does not need to match the DeviceServer name or device
|
|
52
|
+
class name. `log_ctrl` uses the `log_name` exactly as it appears in the
|
|
53
|
+
filename.
|
|
54
|
+
|
|
55
|
+
## Main features
|
|
56
|
+
|
|
57
|
+
- `log_names()`: Get the list of `log_name` values from existing log
|
|
58
|
+
files.
|
|
59
|
+
- `dates(log_name)`: Get the list of rotation dates for the specified
|
|
60
|
+
`log_name`.
|
|
61
|
+
- `exists(log_name, date=None)`: Check whether the current log or a
|
|
62
|
+
log for a specified date exists.
|
|
63
|
+
- `tail(log_name, lines=100, date=None)`: Get the end of a log as a
|
|
64
|
+
string.
|
|
65
|
+
- `raw_files()`: List all files under the log directory as relative
|
|
66
|
+
paths.
|
|
67
|
+
- `read(log_name, date=None)`: Read a log file as `bytes`.
|
|
68
|
+
- `read_raw(relative_path)`: Read an arbitrary file confirmed by
|
|
69
|
+
`raw_files()` as `bytes`.
|
|
70
|
+
|
|
71
|
+
Large log files are transferred in chunks using `grpc_frame`
|
|
72
|
+
`StreamCall`. Client-side code does not need to handle the stream
|
|
73
|
+
directly; `read()` and `read_raw()` join the received chunks and return
|
|
74
|
+
them as `bytes`.
|
|
75
|
+
|
|
76
|
+
## Installation
|
|
77
|
+
|
|
78
|
+
Install in an environment where `grpc_frame` is available.
|
|
79
|
+
|
|
80
|
+
``` bash
|
|
81
|
+
python -m pip install .
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
For development, use an editable install:
|
|
85
|
+
|
|
86
|
+
``` bash
|
|
87
|
+
python -m pip install -e .
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Starting LogServer
|
|
91
|
+
|
|
92
|
+
``` python
|
|
93
|
+
from log_ctrl.server_grpc import log_grpc_server
|
|
94
|
+
|
|
95
|
+
GRPC_HOST = "0.0.0.0"
|
|
96
|
+
GRPC_PORT = 50060
|
|
97
|
+
LOG_DIR = r"C:\opt\ese774\log"
|
|
98
|
+
|
|
99
|
+
log_grpc_server(
|
|
100
|
+
grpc_host=GRPC_HOST,
|
|
101
|
+
grpc_port=GRPC_PORT,
|
|
102
|
+
log_dir=LOG_DIR,
|
|
103
|
+
)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
If `logger` is omitted, the standard `logging` module is used. To use an
|
|
107
|
+
existing logger, pass it with `logger=`.
|
|
108
|
+
|
|
109
|
+
## Client
|
|
110
|
+
|
|
111
|
+
Use `DeviceProxy` as the transparent `grpc_frame` client.
|
|
112
|
+
|
|
113
|
+
``` python
|
|
114
|
+
from log_ctrl.server_grpc import DeviceProxy
|
|
115
|
+
|
|
116
|
+
client = DeviceProxy(
|
|
117
|
+
"log",
|
|
118
|
+
server_ip="127.0.0.1",
|
|
119
|
+
server_port=50060,
|
|
120
|
+
set_timeout_sec=10.0,
|
|
121
|
+
async_mode=False,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
try:
|
|
125
|
+
log_names = client.log_names()
|
|
126
|
+
print(log_names)
|
|
127
|
+
|
|
128
|
+
if len(log_names) > 0:
|
|
129
|
+
log_name = log_names[0]
|
|
130
|
+
|
|
131
|
+
print(client.dates(log_name))
|
|
132
|
+
|
|
133
|
+
if client.exists(log_name):
|
|
134
|
+
data = client.read(log_name)
|
|
135
|
+
print(len(data))
|
|
136
|
+
|
|
137
|
+
finally:
|
|
138
|
+
client.close()
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The names returned by `log_names()` are not limited to names for which a
|
|
142
|
+
current `<log_name>.log` file exists. A name is also included when only
|
|
143
|
+
rotated log files remain. Check `exists(log_name)` as needed before
|
|
144
|
+
reading the current log.
|
|
145
|
+
|
|
146
|
+
## API
|
|
147
|
+
|
|
148
|
+
``` python
|
|
149
|
+
client.log_names()
|
|
150
|
+
client.dates(log_name)
|
|
151
|
+
|
|
152
|
+
client.exists(log_name)
|
|
153
|
+
client.exists(log_name, date="2026-04-06")
|
|
154
|
+
|
|
155
|
+
client.tail(log_name, lines=100)
|
|
156
|
+
client.tail(log_name, lines=100, date="2026-04-06")
|
|
157
|
+
|
|
158
|
+
client.raw_files()
|
|
159
|
+
|
|
160
|
+
client.read(log_name)
|
|
161
|
+
client.read(log_name, date="2026-04-06")
|
|
162
|
+
|
|
163
|
+
client.read_raw("cobotta4_server.log.2026-04-06")
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
`read()` and `read_raw()` return `bytes`. To handle a log as text,
|
|
167
|
+
decode it on the client using the appropriate character encoding.
|
|
168
|
+
|
|
169
|
+
``` python
|
|
170
|
+
text = client.read(log_name).decode("utf-8")
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
`tail()` is decoded on the server using the configured `encoding` and
|
|
174
|
+
returns `str`.
|
|
175
|
+
|
|
176
|
+
## Documentation
|
|
177
|
+
|
|
178
|
+
Sphinx documentation is available under `docs/`.
|
|
179
|
+
|
|
180
|
+
- `docs/index.md`
|
|
181
|
+
- `docs/quickstart.md`
|
|
182
|
+
- `docs/usage.md`
|
|
183
|
+
- `docs/rotation.md`
|
|
184
|
+
- `docs/architecture.md`
|
|
185
|
+
|
|
186
|
+
## License
|
|
187
|
+
|
|
188
|
+
See `LICENSE`.
|
|
@@ -3,12 +3,14 @@ requires = ["setuptools>=40.8"]
|
|
|
3
3
|
build-backend = "setuptools.build_meta"
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
|
-
name = "
|
|
7
|
-
version = "0.0.
|
|
6
|
+
name = "log-ctrl"
|
|
7
|
+
version = "0.0.4"
|
|
8
|
+
|
|
8
9
|
description = "gRPC server and proxy for reading x_logger rotating log files by device class."
|
|
9
10
|
readme = "README.md"
|
|
10
11
|
requires-python = ">=3.6"
|
|
11
12
|
license = { file = "LICENSE" }
|
|
13
|
+
|
|
12
14
|
authors = [
|
|
13
15
|
{ name = "Kengo NAKADA", email = "kengo.nakada@email.com" }
|
|
14
16
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
|
-
Name:
|
|
3
|
-
Version: 0.0.
|
|
2
|
+
Name: log-ctrl
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary: gRPC server and proxy for reading x_logger rotating log files by device class.
|
|
5
5
|
Author-email: Kengo NAKADA <kengo.nakada@email.com>
|
|
6
6
|
License: Apache License
|
|
@@ -230,16 +230,15 @@ Dynamic: license-file
|
|
|
230
230
|
|
|
231
231
|
# log_ctrl
|
|
232
232
|
|
|
233
|
-
[](https://github.com/ohara-lab-su/log_ctrl/blob/main/README.
|
|
234
|
-
[](https://github.com/ohara-lab-su/log_ctrl/blob/main/README.md)
|
|
233
|
+
[](https://github.com/ohara-lab-su/log_ctrl/blob/main/README.md)
|
|
234
|
+
[](https://github.com/ohara-lab-su/log_ctrl/blob/main/README.ja.md)
|
|
235
235
|
|
|
236
|
-
`log_ctrl`
|
|
237
|
-
|
|
238
|
-
を使ってネットワーク越しに参照するためのパッケージです。
|
|
236
|
+
`log_ctrl` is a package for accessing log files stored in a specified
|
|
237
|
+
log directory over a network using `grpc_frame`.
|
|
239
238
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
239
|
+
It does not add log retrieval RPCs to the DeviceServer or application
|
|
240
|
+
that writes the logs. `log_ctrl` runs as an independent, read-only gRPC
|
|
241
|
+
server that accesses existing log files.
|
|
243
242
|
|
|
244
243
|
``` text
|
|
245
244
|
application / DeviceServer
|
|
@@ -263,9 +262,9 @@ C:\opt\ese774\log
|
|
|
263
262
|
DeviceProxy("log", ...)
|
|
264
263
|
```
|
|
265
264
|
|
|
266
|
-
##
|
|
265
|
+
## Log names
|
|
267
266
|
|
|
268
|
-
`log_ctrl
|
|
267
|
+
In `log_ctrl`, the part before `.log` is called the `log_name`.
|
|
269
268
|
|
|
270
269
|
``` text
|
|
271
270
|
cobotta4_server.log
|
|
@@ -273,47 +272,52 @@ cobotta4_server.log
|
|
|
273
272
|
log_name
|
|
274
273
|
```
|
|
275
274
|
|
|
276
|
-
|
|
275
|
+
Rotated log files use the following format:
|
|
277
276
|
|
|
278
277
|
``` text
|
|
279
278
|
<log_name>.log.YYYY-MM-DD
|
|
280
279
|
```
|
|
281
280
|
|
|
282
|
-
`log_name`
|
|
283
|
-
|
|
284
|
-
|
|
281
|
+
The `log_name` does not need to match the DeviceServer name or device
|
|
282
|
+
class name. `log_ctrl` uses the `log_name` exactly as it appears in the
|
|
283
|
+
filename.
|
|
285
284
|
|
|
286
|
-
##
|
|
285
|
+
## Main features
|
|
287
286
|
|
|
288
|
-
- `log_names()
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
- `
|
|
293
|
-
|
|
294
|
-
- `
|
|
295
|
-
|
|
296
|
-
|
|
287
|
+
- `log_names()`: Get the list of `log_name` values from existing log
|
|
288
|
+
files.
|
|
289
|
+
- `dates(log_name)`: Get the list of rotation dates for the specified
|
|
290
|
+
`log_name`.
|
|
291
|
+
- `exists(log_name, date=None)`: Check whether the current log or a
|
|
292
|
+
log for a specified date exists.
|
|
293
|
+
- `tail(log_name, lines=100, date=None)`: Get the end of a log as a
|
|
294
|
+
string.
|
|
295
|
+
- `raw_files()`: List all files under the log directory as relative
|
|
296
|
+
paths.
|
|
297
|
+
- `read(log_name, date=None)`: Read a log file as `bytes`.
|
|
298
|
+
- `read_raw(relative_path)`: Read an arbitrary file confirmed by
|
|
299
|
+
`raw_files()` as `bytes`.
|
|
297
300
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
+
Large log files are transferred in chunks using `grpc_frame`
|
|
302
|
+
`StreamCall`. Client-side code does not need to handle the stream
|
|
303
|
+
directly; `read()` and `read_raw()` join the received chunks and return
|
|
304
|
+
them as `bytes`.
|
|
301
305
|
|
|
302
|
-
##
|
|
306
|
+
## Installation
|
|
303
307
|
|
|
304
|
-
`grpc_frame`
|
|
308
|
+
Install in an environment where `grpc_frame` is available.
|
|
305
309
|
|
|
306
310
|
``` bash
|
|
307
311
|
python -m pip install .
|
|
308
312
|
```
|
|
309
313
|
|
|
310
|
-
|
|
314
|
+
For development, use an editable install:
|
|
311
315
|
|
|
312
316
|
``` bash
|
|
313
317
|
python -m pip install -e .
|
|
314
318
|
```
|
|
315
319
|
|
|
316
|
-
## LogServer
|
|
320
|
+
## Starting LogServer
|
|
317
321
|
|
|
318
322
|
``` python
|
|
319
323
|
from log_ctrl.server_grpc import log_grpc_server
|
|
@@ -329,12 +333,12 @@ log_grpc_server(
|
|
|
329
333
|
)
|
|
330
334
|
```
|
|
331
335
|
|
|
332
|
-
`logger`
|
|
333
|
-
|
|
336
|
+
If `logger` is omitted, the standard `logging` module is used. To use an
|
|
337
|
+
existing logger, pass it with `logger=`.
|
|
334
338
|
|
|
335
|
-
##
|
|
339
|
+
## Client
|
|
336
340
|
|
|
337
|
-
`
|
|
341
|
+
Use `DeviceProxy` as the transparent `grpc_frame` client.
|
|
338
342
|
|
|
339
343
|
``` python
|
|
340
344
|
from log_ctrl.server_grpc import DeviceProxy
|
|
@@ -364,9 +368,10 @@ finally:
|
|
|
364
368
|
client.close()
|
|
365
369
|
```
|
|
366
370
|
|
|
367
|
-
`log_names()`
|
|
368
|
-
|
|
369
|
-
`exists(log_name)`
|
|
371
|
+
The names returned by `log_names()` are not limited to names for which a
|
|
372
|
+
current `<log_name>.log` file exists. A name is also included when only
|
|
373
|
+
rotated log files remain. Check `exists(log_name)` as needed before
|
|
374
|
+
reading the current log.
|
|
370
375
|
|
|
371
376
|
## API
|
|
372
377
|
|
|
@@ -388,20 +393,19 @@ client.read(log_name, date="2026-04-06")
|
|
|
388
393
|
client.read_raw("cobotta4_server.log.2026-04-06")
|
|
389
394
|
```
|
|
390
395
|
|
|
391
|
-
`read()`
|
|
392
|
-
|
|
393
|
-
decode します。
|
|
396
|
+
`read()` and `read_raw()` return `bytes`. To handle a log as text,
|
|
397
|
+
decode it on the client using the appropriate character encoding.
|
|
394
398
|
|
|
395
399
|
``` python
|
|
396
400
|
text = client.read(log_name).decode("utf-8")
|
|
397
401
|
```
|
|
398
402
|
|
|
399
|
-
`tail()`
|
|
400
|
-
|
|
403
|
+
`tail()` is decoded on the server using the configured `encoding` and
|
|
404
|
+
returns `str`.
|
|
401
405
|
|
|
402
|
-
##
|
|
406
|
+
## Documentation
|
|
403
407
|
|
|
404
|
-
Sphinx
|
|
408
|
+
Sphinx documentation is available under `docs/`.
|
|
405
409
|
|
|
406
410
|
- `docs/index.md`
|
|
407
411
|
- `docs/quickstart.md`
|
|
@@ -411,4 +415,4 @@ Sphinx 用文書は `docs/` にあります。
|
|
|
411
415
|
|
|
412
416
|
## License
|
|
413
417
|
|
|
414
|
-
`LICENSE
|
|
418
|
+
See `LICENSE`.
|
log_ctrl-0.0.1/README.md
DELETED
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
# log_ctrl
|
|
2
|
-
|
|
3
|
-
[](https://github.com/ohara-lab-su/log_ctrl/blob/main/README.en.md)
|
|
4
|
-
[](https://github.com/ohara-lab-su/log_ctrl/blob/main/README.md)
|
|
5
|
-
|
|
6
|
-
`log_ctrl`
|
|
7
|
-
は、指定したログディレクトリに保存されているログファイルを、`grpc_frame`
|
|
8
|
-
を使ってネットワーク越しに参照するためのパッケージです。
|
|
9
|
-
|
|
10
|
-
ログを書き込む側の DeviceServer やアプリケーションにはログ取得 RPC
|
|
11
|
-
を追加しません。`log_ctrl` は既存のログファイルを read-only
|
|
12
|
-
で参照する独立した gRPC サーバーとして動作します。
|
|
13
|
-
|
|
14
|
-
``` text
|
|
15
|
-
application / DeviceServer
|
|
16
|
-
│
|
|
17
|
-
│ write
|
|
18
|
-
▼
|
|
19
|
-
C:\opt\ese774\log
|
|
20
|
-
├── cobotta4_server.log
|
|
21
|
-
├── cobotta4_server.log.2026-04-06
|
|
22
|
-
├── cobotta4_server2.log
|
|
23
|
-
└── cobotta4_server2.log.2026-06-16
|
|
24
|
-
▲
|
|
25
|
-
│ read only
|
|
26
|
-
│
|
|
27
|
-
LogCtrl
|
|
28
|
-
│
|
|
29
|
-
▼
|
|
30
|
-
log gRPC server
|
|
31
|
-
│
|
|
32
|
-
▼
|
|
33
|
-
DeviceProxy("log", ...)
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## ログ名
|
|
37
|
-
|
|
38
|
-
`log_ctrl` では、`.log` より前の部分を `log_name` と呼びます。
|
|
39
|
-
|
|
40
|
-
``` text
|
|
41
|
-
cobotta4_server.log
|
|
42
|
-
^^^^^^^^^^^^^^^
|
|
43
|
-
log_name
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
ローテーション済みログは次の形式です。
|
|
47
|
-
|
|
48
|
-
``` text
|
|
49
|
-
<log_name>.log.YYYY-MM-DD
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
`log_name` は DeviceServer
|
|
53
|
-
名やデバイスクラス名と一致する必要はありません。`log_ctrl`
|
|
54
|
-
はファイル名として存在する `log_name` をそのまま扱います。
|
|
55
|
-
|
|
56
|
-
## 主な機能
|
|
57
|
-
|
|
58
|
-
- `log_names()` : 実在するログファイルから `log_name` 一覧を取得
|
|
59
|
-
- `dates(log_name)` : 指定した `log_name`
|
|
60
|
-
のローテーション日付一覧を取得
|
|
61
|
-
- `exists(log_name, date=None)` : 現在ログまたは指定日ログの存在確認
|
|
62
|
-
- `tail(log_name, lines=100, date=None)` : ログ末尾を文字列で取得
|
|
63
|
-
- `raw_files()` : ログディレクトリ以下の全ファイルを相対パスで列挙
|
|
64
|
-
- `read(log_name, date=None)` : ログファイル本体を `bytes` で取得
|
|
65
|
-
- `read_raw(relative_path)` : `raw_files()` で確認した任意ファイルを
|
|
66
|
-
`bytes` で取得
|
|
67
|
-
|
|
68
|
-
大きなログファイルは `grpc_frame` の `StreamCall`
|
|
69
|
-
を使ってチャンク転送します。利用側ではストリーム処理を直接扱う必要はなく、`read()`
|
|
70
|
-
/ `read_raw()` が受信したチャンクを結合して `bytes` として返します。
|
|
71
|
-
|
|
72
|
-
## インストール
|
|
73
|
-
|
|
74
|
-
`grpc_frame` を利用可能な環境でインストールします。
|
|
75
|
-
|
|
76
|
-
``` bash
|
|
77
|
-
python -m pip install .
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
開発時は次のように editable install できます。
|
|
81
|
-
|
|
82
|
-
``` bash
|
|
83
|
-
python -m pip install -e .
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
## LogServer の起動
|
|
87
|
-
|
|
88
|
-
``` python
|
|
89
|
-
from log_ctrl.server_grpc import log_grpc_server
|
|
90
|
-
|
|
91
|
-
GRPC_HOST = "0.0.0.0"
|
|
92
|
-
GRPC_PORT = 50060
|
|
93
|
-
LOG_DIR = r"C:\opt\ese774\log"
|
|
94
|
-
|
|
95
|
-
log_grpc_server(
|
|
96
|
-
grpc_host=GRPC_HOST,
|
|
97
|
-
grpc_port=GRPC_PORT,
|
|
98
|
-
log_dir=LOG_DIR,
|
|
99
|
-
)
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
`logger` を省略した場合は標準の `logging` が使用されます。既存の logger
|
|
103
|
-
を使用する場合は `logger=` で渡せます。
|
|
104
|
-
|
|
105
|
-
## クライアント
|
|
106
|
-
|
|
107
|
-
`grpc_frame` の透過クライアントとして `DeviceProxy` を使用します。
|
|
108
|
-
|
|
109
|
-
``` python
|
|
110
|
-
from log_ctrl.server_grpc import DeviceProxy
|
|
111
|
-
|
|
112
|
-
client = DeviceProxy(
|
|
113
|
-
"log",
|
|
114
|
-
server_ip="127.0.0.1",
|
|
115
|
-
server_port=50060,
|
|
116
|
-
set_timeout_sec=10.0,
|
|
117
|
-
async_mode=False,
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
try:
|
|
121
|
-
log_names = client.log_names()
|
|
122
|
-
print(log_names)
|
|
123
|
-
|
|
124
|
-
if len(log_names) > 0:
|
|
125
|
-
log_name = log_names[0]
|
|
126
|
-
|
|
127
|
-
print(client.dates(log_name))
|
|
128
|
-
|
|
129
|
-
if client.exists(log_name):
|
|
130
|
-
data = client.read(log_name)
|
|
131
|
-
print(len(data))
|
|
132
|
-
|
|
133
|
-
finally:
|
|
134
|
-
client.close()
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
`log_names()` で返される名前は、現在の `<log_name>.log`
|
|
138
|
-
が存在する名前だけとは限りません。ローテーション済みファイルだけが残っている場合も一覧に含まれます。現在ログを読む前に必要に応じて
|
|
139
|
-
`exists(log_name)` を確認してください。
|
|
140
|
-
|
|
141
|
-
## API
|
|
142
|
-
|
|
143
|
-
``` python
|
|
144
|
-
client.log_names()
|
|
145
|
-
client.dates(log_name)
|
|
146
|
-
|
|
147
|
-
client.exists(log_name)
|
|
148
|
-
client.exists(log_name, date="2026-04-06")
|
|
149
|
-
|
|
150
|
-
client.tail(log_name, lines=100)
|
|
151
|
-
client.tail(log_name, lines=100, date="2026-04-06")
|
|
152
|
-
|
|
153
|
-
client.raw_files()
|
|
154
|
-
|
|
155
|
-
client.read(log_name)
|
|
156
|
-
client.read(log_name, date="2026-04-06")
|
|
157
|
-
|
|
158
|
-
client.read_raw("cobotta4_server.log.2026-04-06")
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
`read()` と `read_raw()` の戻り値は `bytes`
|
|
162
|
-
です。ログを文字列として扱う場合は、使用している文字コードに合わせてクライアント側で
|
|
163
|
-
decode します。
|
|
164
|
-
|
|
165
|
-
``` python
|
|
166
|
-
text = client.read(log_name).decode("utf-8")
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
`tail()` はサーバー側で設定された `encoding` を使って decode され、`str`
|
|
170
|
-
を返します。
|
|
171
|
-
|
|
172
|
-
## ドキュメント
|
|
173
|
-
|
|
174
|
-
Sphinx 用文書は `docs/` にあります。
|
|
175
|
-
|
|
176
|
-
- `docs/index.md`
|
|
177
|
-
- `docs/quickstart.md`
|
|
178
|
-
- `docs/usage.md`
|
|
179
|
-
- `docs/rotation.md`
|
|
180
|
-
- `docs/architecture.md`
|
|
181
|
-
|
|
182
|
-
## License
|
|
183
|
-
|
|
184
|
-
`LICENSE` を参照してください。
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|