Skip to content

Commit 999e7d7

Browse files
committed
feat(errorlog-utils): add cloudlog
1 parent f88c6ec commit 999e7d7

File tree

9 files changed

+840
-1
lines changed

9 files changed

+840
-1
lines changed

.genlinxrc.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,4 @@ build:
7878
- ./__tests__/include/list
7979
- ./__tests__/include/websocket
8080
- ./__tests__/include/json
81+
- ./__tests__/include/cloudlog
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
PROGRAM_NAME='NAVFoundation.CloudLog'
2+
3+
/*
4+
_ _ _ ___ __
5+
| \ | | ___ _ __ __ _ __ _| |_ ___ / \ \ / /
6+
| \| |/ _ \| '__/ _` |/ _` | __/ _ \ / _ \ \ / /
7+
| |\ | (_) | | | (_| | (_| | || __// ___ \ V /
8+
|_| \_|\___/|_| \__, |\__,_|\__\___/_/ \_\_/
9+
|___/
10+
11+
MIT License
12+
13+
Copyright (c) 2010-2026 Norgate AV
14+
15+
Permission is hereby granted, free of charge, to any person obtaining a copy
16+
of this software and associated documentation files (the "Software"), to deal
17+
in the Software without restriction, including without limitation the rights
18+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19+
copies of the Software, and to permit persons to whom the Software is
20+
furnished to do so, subject to the following conditions
21+
22+
The above copyright notice and this permission notice shall be included in all
23+
copies or substantial portions of the Software.
24+
25+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31+
SOFTWARE.
32+
*/
33+
34+
#IF_NOT_DEFINED __NAV_FOUNDATION_CLOUDLOG__
35+
#DEFINE __NAV_FOUNDATION_CLOUDLOG__ 'NAVFoundation.CloudLog'
36+
37+
#include 'NAVFoundation.Core.axi'
38+
#include 'NAVFoundation.ErrorLogUtils.axi'
39+
#include 'NAVFoundation.DateTimeUtils.axi'
40+
#include 'NAVFoundation.StringUtils.axi'
41+
#include 'NAVFoundation.Json.axi'
42+
#include 'NAVFoundation.CloudLog.h.axi'
43+
44+
45+
/**
46+
* @function NAVCloudLogInit
47+
* @public
48+
* @description Initializes a _NAVCloudLog structure with empty values.
49+
* Useful for creating a clean log structure before populating fields.
50+
*
51+
* @param {_NAVCloudLog} log - The log structure to initialize
52+
*
53+
* @example
54+
* stack_var _NAVCloudLog log
55+
* NAVCloudLogInit(log)
56+
*/
57+
define_function NAVCloudLogInit(_NAVCloudLog log) {
58+
log.id = ''
59+
log.timestamp = ''
60+
log.clientId = ''
61+
log.hostName = ''
62+
log.firmwareVersion = ''
63+
log.systemType = ''
64+
log.ipAddress = ''
65+
log.roomName = ''
66+
log.level = ''
67+
log.message = ''
68+
}
69+
70+
71+
/**
72+
* @function NAVCloudLogValidate
73+
* @public
74+
* @description Validates that the provided strings will fit in the _NAVCloudLog structure.
75+
* Checks clientId, roomName, and message against their maximum field sizes.
76+
*
77+
* @param {char[]} clientId - Client identifier to validate
78+
* @param {char[]} roomName - Room name to validate
79+
* @param {char[]} message - Message to validate
80+
*
81+
* @returns {char} True if all fields are within size limits, false otherwise
82+
*
83+
* @example
84+
* if (NAVCloudLogValidate(clientId, roomName, message)) {
85+
* // Safe to create log
86+
* }
87+
*/
88+
define_function char NAVCloudLogValidate(char clientId[], char roomName[], char message[]) {
89+
if (length_array(clientId) >= NAV_CLOUDLOG_SIZE_CLIENT_ID) {
90+
NAVLibraryFunctionErrorLog(NAV_LOG_LEVEL_WARNING,
91+
__NAV_FOUNDATION_CLOUDLOG__,
92+
'NAVCloudLogValidate',
93+
'clientId exceeds maximum size')
94+
return false
95+
}
96+
97+
if (length_array(roomName) >= NAV_CLOUDLOG_SIZE_ROOM_NAME) {
98+
NAVLibraryFunctionErrorLog(NAV_LOG_LEVEL_WARNING,
99+
__NAV_FOUNDATION_CLOUDLOG__,
100+
'NAVCloudLogValidate',
101+
'roomName exceeds maximum size')
102+
return false
103+
}
104+
105+
if (length_array(message) >= NAV_CLOUDLOG_SIZE_MESSAGE) {
106+
NAVLibraryFunctionErrorLog(NAV_LOG_LEVEL_WARNING,
107+
__NAV_FOUNDATION_CLOUDLOG__,
108+
'NAVCloudLogValidate',
109+
'message exceeds maximum size')
110+
return false
111+
}
112+
113+
return true
114+
}
115+
116+
117+
/**
118+
* @function NAVCloudLogBuild
119+
* @public
120+
* @description Builds a comprehensive cloud log entry with system metadata and serializes it to JSON.
121+
* Automatically collects system information including hostname, firmware version,
122+
* IP address, and generates a unique UUID and timestamp for the log entry.
123+
*
124+
* @param {char[]} clientId - Client identifier for the application or service
125+
* @param {char[]} roomName - Name of the room or location generating the log
126+
* @param {long} level - Log level constant (NAV_LOG_LEVEL_ERROR, NAV_LOG_LEVEL_WARNING, etc.)
127+
* @param {char[]} message - The log message content
128+
*
129+
* @returns {char[NAV_CLOUDLOG_JSON_BUFFER_SIZE]} JSON string representation of the complete log entry
130+
*
131+
* @example
132+
* stack_var char logJson[NAV_CLOUDLOG_JSON_BUFFER_SIZE]
133+
* logJson = NAVCloudLogBuild('MyApp', 'Conference Room A', NAV_LOG_LEVEL_INFO, 'System started')
134+
* // Returns: {"id":"...","timestamp":"...","clientId":"MyApp",...}
135+
*/
136+
define_function char[NAV_CLOUDLOG_JSON_BUFFER_SIZE] NAVCloudLogBuild(char clientId[],
137+
char roomName[],
138+
long level,
139+
char message[]) {
140+
stack_var _NAVController controller
141+
stack_var _NAVCloudLog log
142+
143+
log.id = NAVGetNewGuid()
144+
log.timestamp = NAVDateTimeGetTimestampNow()
145+
log.clientId = NAVTrimString(clientId)
146+
147+
NAVGetControllerInformation(controller)
148+
log.hostName = controller.IP.Hostname
149+
150+
log.systemType = NAV_CLOUDLOG_SYSTEM_TYPE_NETLINX
151+
log.firmwareVersion = controller.Information.Version
152+
log.ipAddress = controller.IP.IPAddress
153+
154+
log.roomName = NAVTrimString(roomName)
155+
log.level = NAVGetLogLevel(level)
156+
log.message = message
157+
158+
return NAVCloudLogJsonSerialize(log)
159+
}
160+
161+
162+
/**
163+
* @function NAVCloudLogJsonSerialize
164+
* @public
165+
* @description Serializes a _NAVCloudLog structure to a JSON string format.
166+
* Properly escapes special characters in string fields to ensure
167+
* valid JSON output. Fields escaped: clientId, hostName, firmwareVersion,
168+
* roomName, and message.
169+
*
170+
* @param {_NAVCloudLog} log - The cloud log structure to serialize
171+
*
172+
* @returns {char[NAV_CLOUDLOG_JSON_BUFFER_SIZE]} JSON string representation of the log entry
173+
*
174+
* @example
175+
* stack_var _NAVCloudLog log
176+
* stack_var char json[NAV_CLOUDLOG_JSON_BUFFER_SIZE]
177+
* log.id = NAVGetNewGuid()
178+
* log.message = 'Test message'
179+
* json = NAVCloudLogJsonSerialize(log)
180+
*/
181+
define_function char[NAV_CLOUDLOG_JSON_BUFFER_SIZE] NAVCloudLogJsonSerialize(_NAVCloudLog log) {
182+
stack_var char data[NAV_CLOUDLOG_JSON_BUFFER_SIZE]
183+
184+
// Build JSON object with proper escaping for all string fields
185+
data = '{'
186+
data = "data, '"', NAV_CLOUDLOG_FIELD_ID, '":"', log.id, '"'"
187+
data = "data, ',"', NAV_CLOUDLOG_FIELD_TIMESTAMP, '":"', log.timestamp, '"'"
188+
data = "data, ',"', NAV_CLOUDLOG_FIELD_CLIENT_ID, '":"', NAVJsonEscapeString(log.clientId), '"'"
189+
data = "data, ',"', NAV_CLOUDLOG_FIELD_HOST_NAME, '":"', NAVJsonEscapeString(log.hostName), '"'"
190+
data = "data, ',"', NAV_CLOUDLOG_FIELD_SYSTEM_TYPE, '":"', log.systemType, '"'"
191+
data = "data, ',"', NAV_CLOUDLOG_FIELD_FIRMWARE_VERSION, '":"', NAVJsonEscapeString(log.firmwareVersion), '"'"
192+
data = "data, ',"', NAV_CLOUDLOG_FIELD_IP_ADDRESS, '":"', log.ipAddress, '"'"
193+
data = "data, ',"', NAV_CLOUDLOG_FIELD_ROOM_NAME, '":"', NAVJsonEscapeString(log.roomName), '"'"
194+
data = "data, ',"', NAV_CLOUDLOG_FIELD_LEVEL, '":"', log.level, '"'"
195+
data = "data, ',"', NAV_CLOUDLOG_FIELD_MESSAGE, '":"', NAVJsonEscapeString(log.message), '"'"
196+
data = "data, '}'"
197+
198+
return data
199+
}
200+
201+
202+
/**
203+
* @function NAVCloudLog
204+
* @public
205+
* @description Sends a log command to a device for processing by a cloud logger module.
206+
* Formats the command as 'LOG-<level>,<message>' where level is the string
207+
* representation of the log level (error, warning, info, debug).
208+
*
209+
* @param {dev} device - The device to send the log command to (typically a cloud logger module)
210+
* @param {long} level - Log level constant (NAV_LOG_LEVEL_ERROR, NAV_LOG_LEVEL_WARNING, etc.)
211+
* @param {char[]} message - The log message to send
212+
*
213+
* @example
214+
* // Send an error log to the cloud logger module
215+
* NAVCloudLog(vdvCloudLogger, NAV_LOG_LEVEL_ERROR, 'Connection failed')
216+
* // Sends command: "LOG-error,Connection failed"
217+
*/
218+
define_function NAVCloudLog(dev device, long level, char message[]) {
219+
NAVCommand(device, "NAV_CLOUDLOG_COMMAND_PREFIX, '-', NAVGetLogLevel(level), ',', message")
220+
}
221+
222+
223+
#END_IF // __NAV_FOUNDATION_CLOUDLOG__
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
PROGRAM_NAME='NAVFoundation.CloudLog.h'
2+
3+
/*
4+
_ _ _ ___ __
5+
| \ | | ___ _ __ __ _ __ _| |_ ___ / \ \ / /
6+
| \| |/ _ \| '__/ _` |/ _` | __/ _ \ / _ \ \ / /
7+
| |\ | (_) | | | (_| | (_| | || __// ___ \ V /
8+
|_| \_|\___/|_| \__, |\__,_|\__\___/_/ \_\_/
9+
|___/
10+
11+
MIT License
12+
13+
Copyright (c) 2010-2026 Norgate AV
14+
15+
Permission is hereby granted, free of charge, to any person obtaining a copy
16+
of this software and associated documentation files (the "Software"), to deal
17+
in the Software without restriction, including without limitation the rights
18+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19+
copies of the Software, and to permit persons to whom the Software is
20+
furnished to do so, subject to the following conditions
21+
22+
The above copyright notice and this permission notice shall be included in all
23+
copies or substantial portions of the Software.
24+
25+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31+
SOFTWARE.
32+
*/
33+
34+
#IF_NOT_DEFINED __NAV_FOUNDATION_CLOUDLOG_H__
35+
#DEFINE __NAV_FOUNDATION_CLOUDLOG_H__ 'NAVFoundation.CloudLog.h'
36+
37+
38+
DEFINE_CONSTANT
39+
40+
// System type identifier
41+
constant char NAV_CLOUDLOG_SYSTEM_TYPE_NETLINX[] = 'NetLinx'
42+
43+
// Command prefix for log commands sent to cloud logger modules
44+
constant char NAV_CLOUDLOG_COMMAND_PREFIX[] = 'LOG'
45+
46+
// Maximum buffer size for serialized JSON log data
47+
constant integer NAV_CLOUDLOG_JSON_BUFFER_SIZE = 2048
48+
49+
// Struct field size constants (matching _NAVCloudLog struct)
50+
constant integer NAV_CLOUDLOG_SIZE_ID = 40
51+
constant integer NAV_CLOUDLOG_SIZE_TIMESTAMP = 32
52+
constant integer NAV_CLOUDLOG_SIZE_CLIENT_ID = 128
53+
constant integer NAV_CLOUDLOG_SIZE_HOST_NAME = 128
54+
constant integer NAV_CLOUDLOG_SIZE_FIRMWARE_VERSION = 64
55+
constant integer NAV_CLOUDLOG_SIZE_SYSTEM_TYPE = 64
56+
constant integer NAV_CLOUDLOG_SIZE_IP_ADDRESS = 45
57+
constant integer NAV_CLOUDLOG_SIZE_ROOM_NAME = 128
58+
constant integer NAV_CLOUDLOG_SIZE_LEVEL = 8
59+
constant integer NAV_CLOUDLOG_SIZE_MESSAGE = 512
60+
61+
// JSON field names
62+
constant char NAV_CLOUDLOG_FIELD_ID[] = 'id'
63+
constant char NAV_CLOUDLOG_FIELD_TIMESTAMP[] = 'timestamp'
64+
constant char NAV_CLOUDLOG_FIELD_CLIENT_ID[] = 'clientId'
65+
constant char NAV_CLOUDLOG_FIELD_HOST_NAME[] = 'hostName'
66+
constant char NAV_CLOUDLOG_FIELD_SYSTEM_TYPE[] = 'systemType'
67+
constant char NAV_CLOUDLOG_FIELD_FIRMWARE_VERSION[] = 'firmwareVersion'
68+
constant char NAV_CLOUDLOG_FIELD_IP_ADDRESS[] = 'ipAddress'
69+
constant char NAV_CLOUDLOG_FIELD_ROOM_NAME[] = 'roomName'
70+
constant char NAV_CLOUDLOG_FIELD_LEVEL[] = 'level'
71+
constant char NAV_CLOUDLOG_FIELD_MESSAGE[] = 'message'
72+
73+
74+
DEFINE_TYPE
75+
76+
/**
77+
* @struct _NAVCloudLog
78+
* @description Structure representing a cloud log entry with comprehensive system metadata.
79+
* Contains all necessary information for remote logging including unique ID,
80+
* timestamp, system information, and the log message itself.
81+
*
82+
* @property {char[40]} id - Unique identifier for the log entry (UUID v4 format, 36 chars)
83+
* @property {char[32]} timestamp - ISO 8601 formatted timestamp of when the log was created (~24 chars)
84+
* @property {char[128]} clientId - Client identifier for grouping logs by application or service
85+
* @property {char[128]} hostName - Hostname of the controller generating the log
86+
* @property {char[64]} firmwareVersion - Firmware version of the controller
87+
* @property {char[64]} systemType - System type identifier (e.g., 'NetLinx')
88+
* @property {char[45]} ipAddress - IP address of the controller (supports IPv4 and IPv6)
89+
* @property {char[128]} roomName - Name of the room or location where the log was generated
90+
* @property {char[8]} level - Log level (error, warning, info, debug)
91+
* @property {char[512]} message - The actual log message content
92+
*/
93+
struct _NAVCloudLog {
94+
char id[40]
95+
char timestamp[32]
96+
char clientId[128]
97+
char hostName[128]
98+
char firmwareVersion[64]
99+
char systemType[64]
100+
char ipAddress[45]
101+
char roomName[128]
102+
char level[8]
103+
char message[512]
104+
}
105+
106+
107+
#END_IF // __NAV_FOUNDATION_CLOUDLOG_H__

__tests__/NAVFoundation-Tests.apw

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -876,7 +876,7 @@
876876
<Comments></Comments>
877877
</File>
878878
</System>
879-
<System IsActive="true" Platform="Netlinx" Transport="Serial" TransportEx="TCPIP">
879+
<System IsActive="false" Platform="Netlinx" Transport="Serial" TransportEx="TCPIP">
880880
<Identifier>Json</Identifier>
881881
<SysID>0</SysID>
882882
<TransTCPIP>0.0.0.0</TransTCPIP>
@@ -898,5 +898,27 @@
898898
<Comments></Comments>
899899
</File>
900900
</System>
901+
<System IsActive="true" Platform="Netlinx" Transport="Serial" TransportEx="TCPIP">
902+
<Identifier>CloudLog</Identifier>
903+
<SysID>0</SysID>
904+
<TransTCPIP>0.0.0.0</TransTCPIP>
905+
<TransSerial>COM1,115200,8,None,1,None</TransSerial>
906+
<TransTCPIPEx>192.168.10.37|1319|1|NX-2200|ZGFtaWVu|QXZtYWNoMW5lcyE3MjQ5</TransTCPIPEx>
907+
<TransSerialEx>COM1|38400|8|None|1|None||</TransSerialEx>
908+
<TransUSBEx>|||||</TransUSBEx>
909+
<TransVNMEx>10.0.0.1|1|&lt;Default&gt;</TransVNMEx>
910+
<VirtualNetLinxMasterFlag>false</VirtualNetLinxMasterFlag>
911+
<VNMSystemID>1</VNMSystemID>
912+
<VNMIPAddress>10.0.0.1</VNMIPAddress>
913+
<VNMMaskAddress>255.255.255.0</VNMMaskAddress>
914+
<UserName></UserName>
915+
<Password></Password>
916+
<Comments></Comments>
917+
<File CompileType="Netlinx" Type="MasterSrc">
918+
<Identifier>cloudlog</Identifier>
919+
<FilePathName>src\cloudlog.axs</FilePathName>
920+
<Comments></Comments>
921+
</File>
922+
</System>
901923
</Project>
902924
</Workspace>

0 commit comments

Comments
 (0)