Skip to content

Commit 7aa061f

Browse files
committed
Trying to get logging messages from C++ to Python. Not working currently because the pointer to the file descriptor is not the same across modules.
1 parent 5a4d6d0 commit 7aa061f

File tree

9 files changed

+123
-12
lines changed

9 files changed

+123
-12
lines changed

ppafm/GridUtils.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import numpy as np
66

77
from . import cpp_utils
8-
from .logging_utils import get_logger
8+
from .logging_utils import CppLogger, get_logger
99

1010
logger = get_logger("GridUtils")
1111

@@ -160,5 +160,6 @@ def sphericalHist(data, center, dr, n):
160160

161161
def readNumsUpTo(filename, dimensions, noline):
162162
N_arry = np.zeros((dimensions[0] * dimensions[1] * dimensions[2]), dtype=np.double)
163-
lib.ReadNumsUpTo_C(filename.encode(), N_arry, dimensions, noline)
163+
with CppLogger("GridUtils"):
164+
lib.ReadNumsUpTo_C(filename.encode(), N_arry, dimensions, noline)
164165
return N_arry

ppafm/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#!/usr/bin/python
22

3-
# Importing the logging utils sets up the default root logger
4-
from . import logging_utils
53
from .common import *
4+
from .logging_utils import _init_logging
65
from .version import __version__
6+
7+
_init_logging()

ppafm/cpp/GridUtils.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//#include <string.h>
44

55
#include "Grid.h"
6+
#include "logging.h"
67

78
#include <locale.h>
89

@@ -42,8 +43,8 @@ extern "C" {
4243
int nx=dims[0];
4344
int ny=dims[1];
4445
int nz=dims[2];
45-
printf ("FileRead program: reading %s file\n", fname);
46-
printf ("XYZ dimensions are %d %d %d\n", dims[0], dims[1], dims[2]);
46+
log_info ("FileRead program: reading %s file\n", fname);
47+
log_info ("XYZ dimensions are %d %d %d\n", dims[0], dims[1], dims[2]);
4748
f=fopen(fname, "r");
4849
if (f==NULL) {
4950
fprintf(stderr, "Can't open the file %s", fname);

ppafm/cpp/Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ CPPFLAGS= -fPIC -std=c++11 -O2 -mtune=native -fopenmp
99
LDFLAGS= -shared -fopenmp
1010

1111

12-
all: PP GU fitting_ fitSpline_
12+
all: PP GU fitting_ fitSpline_ logging_
1313

1414
PP: ProbeParticle.o
1515

@@ -19,6 +19,8 @@ fitting_: fitting.o
1919

2020
fitSpline_: fitSpline.o
2121

22+
logging_: logging.o
23+
2224
# .o files depend on .cpp files with same prefix
2325
# $@ target, $< prerequisite, $* matched stencil
2426
%.o:: %.cpp

ppafm/cpp/logging

120 KB
Binary file not shown.

ppafm/cpp/logging.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
#include "logging.h"
3+
4+
extern "C"{
5+
6+
void set_log_fd(int fd) {
7+
set_log_fd_(fd);
8+
}
9+
10+
void test_log() {
11+
log_info("test message 1");
12+
// log_debug("test message 2\nanother line");
13+
}
14+
15+
}

ppafm/cpp/logging.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
2+
#ifndef logging_h
3+
#define logging_h
4+
5+
#include <stdio.h>
6+
#include <stdarg.h>
7+
8+
#include <string>
9+
10+
int log_fd = 1;
11+
12+
void log(const char* log_level, const char* format, ...) {
13+
std::string log_level_str = "LOG_ENTRY_" + std::string(log_level) + std::string(" ");
14+
std::string format_str = log_level_str + std::string(format);
15+
va_list arg_list;
16+
va_start(arg_list, format);
17+
printf("log_fd %d %p\n", log_fd, &log_fd);
18+
vdprintf(log_fd, format_str.c_str(), arg_list);
19+
}
20+
21+
void log_info(const char* format, ...) {
22+
va_list arg_list;
23+
va_start(arg_list, format);
24+
log("INFO", format, arg_list);
25+
}
26+
27+
void set_log_fd_(int fd) {
28+
printf("Setting fd %d %d %p\n", log_fd, fd, &log_fd);
29+
log_fd = fd;
30+
printf("Setting fd %d %d %p\n", log_fd, fd, &log_fd);
31+
}
32+
33+
#endif

ppafm/cpp_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
logger.debug(f" PACKAGE_PATH = {PACKAGE_PATH}")
3030
logger.debug(f" CPP_PATH = {CPP_PATH}")
3131

32-
cpp_modules = {"PP": "ProbeParticle", "GU": "GridUtils", "fitting": "fitting", "fitSpline": "fitSpline"}
32+
cpp_modules = {"PP": "ProbeParticle", "GU": "GridUtils", "fitting": "fitting", "fitSpline": "fitSpline", "logging": "logging"}
3333
"""Dictionary of C++ extension modules. Keys are targets for make and values are module names."""
3434

3535

ppafm/logging_utils.py

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import logging
22
import os
33
import sys
4+
import tempfile
45
from typing import Any, Optional, Union
56

67
# Setup the root logger for the ppafm package. All other loggers will be derived from this one.
@@ -15,6 +16,8 @@
1516
_perf_log_format = "[%(asctime)s - %(name)s] %(message)s"
1617
_perf_log_enabled = False
1718

19+
lib = None
20+
1821

1922
def configure_logging(
2023
level: Optional[Union[int, str]] = None,
@@ -45,7 +48,7 @@ def configure_logging(
4548

4649
if level is None:
4750
try:
48-
level = os.environ["PPAFM_LOG_LEVEL"]
51+
level = os.environ["PPAFM_LOG_LEVEL"].upper()
4952
except KeyError:
5053
level = logging.INFO
5154
_root_logger.setLevel(level)
@@ -95,9 +98,64 @@ def configure_logging(
9598
_log_handler.setFormatter(logging.Formatter(fmt=_log_format))
9699

97100

98-
# This sets the logging level immediately from environment variable or defaults to INFO.
99-
# Also sets the message format.
100-
configure_logging()
101+
def _init_logging():
102+
103+
global lib
104+
if lib is not None:
105+
return
106+
107+
configure_logging()
108+
109+
# We have to do this import here, or otherwise we get a circular import
110+
from .cpp_utils import get_cdll
111+
112+
lib = get_cdll("logging")
113+
lib.set_log_fd(sys.stdout.fileno())
114+
115+
with CppLogger("test_logger"):
116+
lib.test_log()
117+
118+
119+
def _get_lib():
120+
if lib is None:
121+
raise RuntimeError("Logging not initialized")
122+
return lib
123+
124+
125+
class CppLogger:
126+
"""Context manager for redirecting logging events in C++ to Python logging."""
127+
128+
def __init__(self, logger_name: str):
129+
self.logger = get_logger(logger_name)
130+
self.lib = _get_lib()
131+
132+
def __enter__(self):
133+
self.log = tempfile.TemporaryFile()
134+
self.lib.set_log_fd(self.log.fileno())
135+
136+
def __exit__(self, exc_type, exc_value, exc_traceback):
137+
self.log.seek(0)
138+
139+
# Read file line-by-line and convert messages to logging events
140+
log_level = logging.INFO
141+
msg = ""
142+
for line in self.log:
143+
line = line.decode().strip()
144+
if line.startswith("LOG_ENTRY_"):
145+
if msg:
146+
self.logger.log(log_level, msg)
147+
msg = ""
148+
line = line.removeprefix("LOG_ENTRY_")
149+
level_str, msg = line.split(" ", maxsplit=1)
150+
log_level = getattr(logging, level_str)
151+
else:
152+
msg += f"\n{line}"
153+
if msg:
154+
self.logger.log(log_level, msg)
155+
156+
self.log.close()
157+
158+
self.lib.set_log_fd(sys.stdout.fileno())
101159

102160

103161
def get_logger(name: str) -> logging.Logger:

0 commit comments

Comments
 (0)