Skip to content

Commit 4bfea50

Browse files
authored
Merge pull request #12 from sy-c/master
swig bindings update
2 parents 0dd5577 + 9094590 commit 4bfea50

File tree

10 files changed

+3230
-51
lines changed

10 files changed

+3230
-51
lines changed

CMakeLists.txt

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ if(NOT COMMON_INCLUDE_DIRS)
8989
set(COMMON_INCLUDE_DIRS ${COMMON_STANDALONE_INCLUDE_DIRS})
9090
endif()
9191
set(INFOLOGGER_INCLUDE_DIRS_PUBLIC include)
92-
set(INFOLOGGER_INCLUDE_DIRS_PRIVATE ${COMMON_INCLUDE_DIRS})
92+
set(INFOLOGGER_INCLUDE_DIRS_PRIVATE ${COMMON_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/src)
9393
set(INFOLOGGER_INCLUDE_DIRS ${INFOLOGGER_INCLUDE_DIRS_PUBLIC} ${INFOLOGGER_INCLUDE_DIRS_PRIVATE})
9494

9595

@@ -100,6 +100,7 @@ set(INFOLOGGER_INCLUDE_DIRS ${INFOLOGGER_INCLUDE_DIRS_PUBLIC} ${INFOLOGGER_INCLU
100100
# object file: client (to infoLoggerD)
101101
add_library (objInfoLoggerClient OBJECT
102102
src/InfoLogger.cxx
103+
src/InfoLoggerScripting.cxx
103104
src/InfoLoggerContext.cxx
104105
src/InfoLoggerClient.cxx
105106
src/infoLoggerMessageDecode.c
@@ -333,6 +334,29 @@ if(SWIG_FOUND)
333334
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/infoLoggerForGo.go DESTINATION ${CMAKE_INSTALL_LIBDIR})
334335
endif()
335336

337+
#library for Javascript / node.js
338+
find_program(NODE_EXECUTABLE node)
339+
get_filename_component(NODE_DIR ${NODE_EXECUTABLE} DIRECTORY)
340+
find_path(NODEJS_INCLUDE_DIRS NAMES node.h PATHS ${Nodejs_ROOT} ${Nodejs_ROOT}/include ${NODE_DIR}/../include/node)
341+
if (NODEJS_INCLUDE_DIRS)
342+
message("Bindings for node.js will be generated")
343+
message("Using NODEJS_INCLUDE_DIRS=${NODEJS_INCLUDE_DIRS}")
344+
if (${SWIG_VERSION} VERSION_LESS "4.0.0")
345+
message("SWIG>=4.0.0 needed to generate node.js wrapper, reusing cached one")
346+
set(SWIG_MODULE_infoLoggerForNodejs_REAL_NAME infoLoggerForNodejs)
347+
add_library (infoLoggerForNodejs SHARED src/infoLoggerJAVASCRIPT_wrap.cxx ${INFOLOGGER_LIB_OBJECTS})
348+
target_include_directories(${SWIG_MODULE_infoLoggerForNodejs_REAL_NAME} PRIVATE ${INFOLOGGER_INCLUDE_DIRS} ${NODEJS_INCLUDE_DIRS})
349+
set_target_properties(${SWIG_MODULE_infoLoggerForNodejs_REAL_NAME} PROPERTIES PREFIX "")
350+
else()
351+
set(CMAKE_SWIG_FLAGS -module infoLoggerForNodejs -v8)
352+
swig_add_library(infoLoggerForNodejs LANGUAGE javascript SOURCES src/infoLogger.i ${INFOLOGGER_LIB_OBJECTS})
353+
endif()
354+
target_include_directories(${SWIG_MODULE_infoLoggerForNodejs_REAL_NAME} PRIVATE ${INFOLOGGER_INCLUDE_DIRS} ${NODEJS_INCLUDE_DIRS})
355+
target_compile_definitions(${SWIG_MODULE_infoLoggerForNodejs_REAL_NAME} PRIVATE -DBUILDING_NODE_EXTENSION)
356+
set_target_properties(${SWIG_MODULE_infoLoggerForNodejs_REAL_NAME} PROPERTIES OUTPUT_NAME infoLogger SUFFIX ".node")
357+
install(TARGETS ${SWIG_MODULE_infoLoggerForNodejs_REAL_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR})
358+
endif()
359+
336360
endif()
337361

338362

doc/README.md

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -216,43 +216,10 @@ The InfoLogger library allows to inject messages directly from programs, as show
216216
217217
Usually, one will only take care of defining the per-message messageOptions struct and a context with appropriate Facility field set, all other being set automatically.
218218
219-
* InfoLogger library is also available for: Tcl, Python, Go.
219+
* InfoLogger library is also available for: Tcl, Python, Go, Node.js.
220220
It allows to log message from scripting languages. A simplified subset of the InfoLogger C++ API is made available through SWIG-generated modules.
221-
Example usage is shown below. Files listed there are available from the infoLogger library installation directory.
221+
Details of the functions accessible from the scripting interface are provided in [a separate document](scriptingAPI.md).
222222
223-
* Tcl
224-
** Library files: infoLoggerForTcl.so
225-
** Code example: (interactive interpreter from the command line)
226-
```
227-
tclsh
228-
load infoLoggerForTcl.so
229-
set logHandle [InfoLogger]
230-
$logHandle logInfo "This is a test"
231-
$logHandle logError "Something went wrong"
232-
```
233-
* Python
234-
** Library files: _infoLoggerForPython.so and infoLoggerForPython.py
235-
** Code example: (interactive interpreter from the command line)
236-
```
237-
python
238-
import infoLoggerForPython
239-
logHandle=infoLoggerForPython.InfoLogger()
240-
logHandle.logInfo("This is a test")
241-
logHandle.logError("Something went wrong")
242-
```
243-
* Go
244-
** Library files: infoLoggerForGo.a and infoLoggerForGo.go (to be copied to ${GOPATH}/src/infoLoggerForGo)
245-
** Build: CGO_LDFLAGS="${GOPATH}/src/infoLoggerForGo/infoLoggerForGo.a -lstdc++" go build
246-
** Code example:
247-
```
248-
package main
249-
import "infoLoggerForGo"
250-
func main() {
251-
var logHandle=infoLoggerForGo.NewInfoLogger()
252-
logHandle.LogInfo("This is a test")
253-
logHandle.LogError("Something went wrong")
254-
}
255-
```
256223
257224
258225
## Configuration

doc/scriptingAPI.md

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
2+
# Scripting API
3+
4+
This document describes the interface to be used to inject messages into the InfoLogger logging system from languages other than C or C++.
5+
6+
Languages currently supported are: Tcl, Python, Go, Javascript (node.js/v8).
7+
8+
A subset of the InfoLogger C++ API (covering most use-cases) is exported using SWIG-generated modules. This avoids the tedious work of manually writing native bindings calling the C++ library for each language (although this is still possible for the brave). InfoLogger provides them ready to use!
9+
10+
This documentation includes a reference of the exported functions, and language-specific example code calling the infoLogger module.
11+
12+
As the C++ interface uses some complex types which can not be transparently converted to all languages, we defined this simplified API with string-only parameters. Although some overhead is added by the generalized used of strings to access the logging message structure fields (compared to the native C++ API), the performance loss is not significant for most situations. A typical machine can still log over 100000 messages per second from a script.
13+
14+
15+
16+
## Classes reference
17+
18+
Default constructor and destructor are not shown here.
19+
20+
* `class InfoLogger`
21+
22+
The main class, to create a handle to the logging system. It provides the methods to inject log messages:
23+
* `logInfo(string message)`
24+
Sends a message with severity Info.
25+
* `logError(string message)`
26+
Sends a message with severity Error.
27+
* `logWarning(string message)`
28+
Sends a message with severity Warning.
29+
* `logFatal(string message)`
30+
Sends a message with severity Fatal.
31+
* `logDebug(string message)`
32+
Sends a message with severity Debug.
33+
* `log(message)`
34+
Sends a message with default severity and metadata.
35+
* `log(InfoLoggerMetadata metadata, string message)`
36+
Send a message with specific metadata (instead of the default, if one defined).
37+
* `setDefaultMetadata(InfoLoggerMetadata metadata)`
38+
Define some metadata to be used by default for all messages.
39+
* `unsetDefaultMetadata()`
40+
Reset the default metadata.
41+
42+
43+
* `class InfoLoggerMetadata`
44+
45+
It is used to specify extra fields associated to a log message. An object of this type can be optionnaly provided to the logging function to set some specific message fields.
46+
* `setField(string key, string value)`
47+
Set one of the field to a specific value. An empty value reset this field to the default. List of valid fields include: *Severity, Level, ErrorCode, SourceFile, SourceLine, Facility, Role, System, Detector, Partition, Run*
48+
* `InfoLoggerMetadata(InfoLoggerMetadata)`
49+
Copy-constructor, to copy an existing InfoLoggerMetadata object to a new one.
50+
51+
52+
## Example usage
53+
54+
Example usage is shown below. Library files listed there are available from the infoLogger library installation directory.
55+
56+
* **Tcl**
57+
* Library files: `infoLoggerForTcl.so`
58+
* Code example: (interactive interpreter from the command line)
59+
```
60+
tclsh
61+
load infoLoggerForTcl.so
62+
set logHandle [InfoLogger]
63+
$logHandle logInfo "This is a test"
64+
$logHandle logError "Something went wrong"
65+
```
66+
* **Python**
67+
* Library files: `_infoLoggerForPython.so` and `infoLoggerForPython.py`
68+
* Code example: (interactive interpreter from the command line)
69+
```
70+
python
71+
import infoLoggerForPython
72+
logHandle=infoLoggerForPython.InfoLogger()
73+
logHandle.logInfo("This is a test")
74+
logHandle.logError("Something went wrong")
75+
```
76+
* **Go**
77+
* Library files: `infoLoggerForGo.a` and `infoLoggerForGo.go`, to be copied to your `${GOPATH}/src/infoLoggerForGo`
78+
* Build: `CGO_LDFLAGS="${GOPATH}/src/infoLoggerForGo/infoLoggerForGo.a -lstdc++" go build`
79+
* Code example:
80+
```
81+
package main
82+
import "infoLoggerForGo"
83+
func main() {
84+
var logHandle=infoLoggerForGo.NewInfoLogger()
85+
logHandle.LogInfo("This is a test")
86+
logHandle.LogError("Something went wrong")
87+
}
88+
```
89+
90+
* **Node.js**
91+
* Library files: `infoLogger.node`
92+
* Code example: (interactive interpreter from the command line)
93+
```
94+
node
95+
var infoLoggerModule=require("infoLogger");
96+
var logHandle=new infoLoggerModule.InfoLogger();
97+
logHandle.logInfo("This is a test");
98+
logHandle.logError("Something went wrong");
99+
```
100+
101+
102+
103+
## Tips
104+
Don't forget to delete the objects if necessary!

include/InfoLogger/InfoLogger.hxx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/// \file InfoLogger.hxx
2-
/// \brief C++ interface for the InfoLogger logging interface.
2+
/// \brief C++ interface for the InfoLogger logging library.
33
///
44
/// See inline documentation, and testInfoLogger.cxx for example usage.
55
///
@@ -74,7 +74,7 @@ class InfoLoggerContext final
7474
/// Update context from current environment information of a different process.
7575
/// This is used internally by command line 'log' utility to tag messages issued by parent process
7676
/// or on stdout by a program which output is piped to stdin of current process and injected in infologger.
77-
/// Fields previously set by user may be overwritten.
77+
/// Fields previously set by user are overwritten.
7878
void refresh(pid_t pid);
7979

8080

@@ -94,9 +94,7 @@ class InfoLoggerContext final
9494

9595
// this simplifies interface to have a single type
9696
// some fields (e.g. run, pid) are stored as integers, but conversion is done by setField
97-
98-
// todo ?
99-
// int getField(FieldName key, std::string &value);
97+
// A field with a blank value (zero-length string) is undefined.
10098

10199

102100
private:
@@ -229,6 +227,8 @@ class InfoLogger
229227

230228
/// Set a field in a message option struct based on its name.
231229
/// If input fieldName valid, and input fieldValue can be parsed, ouput variable is modified accordingly.
230+
/// If fieldValue is blank (zero-length string), the default value is used for the corresponding field.
231+
/// List of valid field names are the strings (1st letter capitalized) corresponding to what is defined in the InfoLoggerMessageOption struct: Severity, Level, ErrorCode, SourceFile, SourceLine
232232
/// \return 0 on success, an error code otherwise.
233233
static int setMessageOption(const char *fieldName, const char *fieldValue, InfoLoggerMessageOption &output);
234234

src/InfoLogger.cxx

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -616,16 +616,45 @@ InfoLogger::Severity InfoLogger::getSeverityFromString(const char *txt) {
616616

617617

618618
int InfoLogger::setMessageOption(const char *fieldName, const char *fieldValue, InfoLoggerMessageOption &output) {
619+
if (fieldName==NULL) {return -1;}
620+
if (fieldValue==NULL) {return -1;}
621+
622+
// in case of blank string, use default value
623+
bool useDefault=false;
624+
if (strlen(fieldValue)==0) {
625+
useDefault=true;
626+
}
627+
619628
if (!strcmp(fieldName,"Severity")) {
620-
output.severity=getSeverityFromString(fieldValue);
629+
if (useDefault) {
630+
output.severity=undefinedMessageOption.severity;
631+
} else {
632+
output.severity=getSeverityFromString(fieldValue);
633+
}
621634
} else if (!strcmp(fieldName,"Level")) {
622-
output.level=atoi(fieldValue);
635+
if (useDefault) {
636+
output.level=undefinedMessageOption.level;
637+
} else {
638+
output.level=atoi(fieldValue);
639+
}
623640
} else if (!strcmp(fieldName,"ErrorCode")) {
624-
output.errorCode=atoi(fieldValue);
641+
if (useDefault) {
642+
output.errorCode=undefinedMessageOption.errorCode;
643+
} else {
644+
output.errorCode=atoi(fieldValue);
645+
}
625646
} else if (!strcmp(fieldName,"SourceFile")) {
626-
output.sourceFile=fieldValue;
647+
if (useDefault) {
648+
output.sourceFile=undefinedMessageOption.sourceFile;
649+
} else {
650+
output.sourceFile=fieldValue;
651+
}
627652
} else if (!strcmp(fieldName,"SourceLine")) {
628-
output.sourceLine=atoi(fieldValue);
653+
if (useDefault) {
654+
output.sourceLine=undefinedMessageOption.sourceLine;
655+
} else {
656+
output.sourceLine=atoi(fieldValue);
657+
}
629658
} else {
630659
return -1;
631660
}

src/InfoLoggerContext.cxx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,10 @@ int InfoLoggerContext::setField(FieldName key, const std::string &value){
155155
partition=value;
156156
} else if (key==FieldName::Run) {
157157
run=-1;
158+
if (value.length()==0) {
159+
// blank value is valid -> leave field unset
160+
return 0;
161+
}
158162
// check input string is a valid run number
159163
int v_run=atoi(value.c_str());
160164
if (v_run<=0) {

0 commit comments

Comments
 (0)