4
4
[ ![ License] ( https://img.shields.io/github/license/diffstorm/processWatchdog )] ( https://github.com/diffstorm/processWatchdog/blob/main/LICENSE )
5
5
[ ![ Language] ( https://img.shields.io/github/languages/top/diffstorm/processWatchdog )] ( https://github.com/diffstorm/processWatchdog )
6
6
7
+ _ It will start, monitor and restart applications if they crash or stop sending heartbeat._
8
+
7
9
The Process Watchdog is a Linux-based utility designed to start, monitor and manage processes specified in a configuration file. It ensures the continuous operation of these processes by periodically checking their status and restarting them if necessary.
8
10
9
11
## Overview
@@ -64,7 +66,7 @@ nWdtApps = 4
64
66
- ` cmd ` : Command to start the application.
65
67
66
68
## Example Heartbeat Message Code
67
- The managed processes must send a message containing their PID over UDP. Below are example heartbeat message codes in various languages.
69
+ The managed processes must send a message containing their PID with prefix ` p ` (Ex: ` p12345 ` ) over UDP. Below are example heartbeat message codes in various languages.
68
70
69
71
### Java
70
72
``` java
@@ -75,14 +77,14 @@ import java.net.InetAddress;
75
77
76
78
public class ProcessHeartbeat {
77
79
public static void sendPIDOverUDP (int port ) {
78
- try {
79
- String host = " 127.0.0.255" ;
80
- String pid = " p" + Long . toString(ProcessHandle . current(). pid());
80
+ try (DatagramSocket socket = new DatagramSocket ()) {
81
+ socket. setBroadcast(true );
82
+
83
+ String pid = " p" + ProcessHandle . current(). pid();
81
84
byte [] data = pid. getBytes();
82
- DatagramSocket socket = new DatagramSocket ();
83
- DatagramPacket packet = new DatagramPacket (data, data. length, InetAddress . getByName(host), port);
84
- socket. send(packet);
85
- socket. close();
85
+
86
+ DatagramPacket packet = new DatagramPacket (data, data. length, InetAddress . getByName(" 127.0.0.255" ), port);
87
+ socket. send(packet);
86
88
} catch (IOException e) {
87
89
e. printStackTrace();
88
90
}
@@ -97,36 +99,37 @@ public class ProcessHeartbeat {
97
99
``` c
98
100
#include < stdio.h>
99
101
#include < stdlib.h>
100
- #include < unistd.h>
101
102
#include < string.h>
102
- #include < arpa/inet.h>
103
- #include < sys/types.h>
104
103
#include < sys/socket.h>
104
+ #include < netinet/in.h>
105
+ #include < arpa/inet.h>
106
+ #include < unistd.h>
105
107
106
108
void sendPIDOverUDP (int port) {
107
109
int sockfd;
108
- struct sockaddr_in servaddr;
109
- char buffer[ 1024] ;
110
- snprintf(buffer, sizeof(buffer), "p%d", getpid());
111
-
112
- // Creating socket file descriptor
113
- if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
110
+ struct sockaddr_in addr;
111
+ socklen_t addr_len = sizeof(addr);
112
+
113
+ // Get the current process ID
114
+ pid_t pid = getpid();
115
+ char pid_str[ 20] ;
116
+ sprintf(pid_str, "p%d", pid);
117
+
118
+ sockfd = socket(AF_INET, SOCK_DGRAM, 0);
119
+ if (sockfd < 0) {
114
120
perror("socket creation failed");
115
121
exit(EXIT_FAILURE);
116
122
}
117
-
118
- memset(&servaddr, 0, sizeof(servaddr));
119
-
120
- // Filling server information
121
- servaddr.sin_family = AF_INET;
122
- servaddr.sin_port = htons(port);
123
- servaddr.sin_addr.s_addr = INADDR_BROADCAST;
124
-
125
- // Send the PID message
126
- if (sendto(sockfd, buffer, strlen(buffer), 0, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
123
+
124
+ memset(&addr, 0, addr_len);
125
+ addr.sin_family = AF_INET;
126
+ addr.sin_port = htons(port);
127
+ addr.sin_addr.s_addr = inet_addr("127.0.0.255");
128
+
129
+ if (sendto(sockfd, pid_str, strlen(pid_str), 0, (struct sockaddr * )&addr, addr_len) < 0) {
127
130
perror("sendto failed");
128
131
}
129
-
132
+
130
133
close(sockfd);
131
134
}
132
135
```
@@ -137,36 +140,39 @@ void sendPIDOverUDP(int port) {
137
140
### C++
138
141
```cpp
139
142
#include <iostream>
140
- #include <unistd.h>
141
143
#include <string>
142
144
#include <cstring>
143
- #include <arpa/inet.h>
144
- #include <sys/types.h>
145
145
#include <sys/socket.h>
146
+ #include <netinet/in.h>
147
+ #include <arpa/inet.h>
148
+ #include <unistd.h>
149
+ #include <cstdlib>
146
150
147
151
void sendPIDOverUDP(int port) {
148
152
int sockfd;
149
- struct sockaddr_in servaddr;
150
- std::string pid_message = "p" + std::to_string(getpid());
151
-
152
- // Creating socket file descriptor
153
- if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
153
+ struct sockaddr_in addr;
154
+ socklen_t addr_len = sizeof(addr);
155
+
156
+ // Get the current process ID
157
+ pid_t pid = getpid();
158
+ std::string pid_str = "p" + std::to_string(pid);
159
+ const char* pid_data = pid_str.c_str();
160
+
161
+ sockfd = socket(AF_INET, SOCK_DGRAM, 0);
162
+ if (sockfd < 0) {
154
163
perror("socket creation failed");
155
164
exit(EXIT_FAILURE);
156
165
}
157
-
158
- memset(&servaddr, 0, sizeof(servaddr));
159
-
160
- // Filling server information
161
- servaddr.sin_family = AF_INET;
162
- servaddr.sin_port = htons(port);
163
- servaddr.sin_addr.s_addr = INADDR_BROADCAST;
164
-
165
- // Send the PID message
166
- if (sendto(sockfd, pid_message.c_str(), pid_message.length(), 0, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
166
+
167
+ memset(&addr, 0, addr_len);
168
+ addr.sin_family = AF_INET;
169
+ addr.sin_port = htons(port);
170
+ addr.sin_addr.s_addr = inet_addr("127.0.0.255");
171
+
172
+ if (sendto(sockfd, pid_data, strlen(pid_data), 0, (struct sockaddr *)&addr, addr_len) < 0) {
167
173
perror("sendto failed");
168
174
}
169
-
175
+
170
176
close(sockfd);
171
177
}
172
178
```
@@ -176,16 +182,24 @@ void sendPIDOverUDP(int port) {
176
182
177
183
### Qt (C++)
178
184
``` cpp
179
- #include < QUdpSocket>
180
185
#include < QCoreApplication>
186
+ #include < QUdpSocket>
187
+ #include < QHostAddress>
188
+ #include < QByteArray>
181
189
#include < QProcess>
182
190
183
- void sendPIDOverUDP (int port) {
184
- QUdpSocket udpSocket;
185
- QString message = "p" + QString::number(QCoreApplication::applicationPid());
186
- QByteArray data = message.toUtf8();
191
+ void sendPIDOverUDP (int port)
192
+ {
193
+ QString host = "127.0.0.255";
194
+ QString pid = "p" + QString::number(QCoreApplication::applicationPid());
195
+ QByteArray data = pid.toUtf8();
187
196
188
- udpSocket.writeDatagram(data, QHostAddress::Broadcast, port);
197
+ QUdpSocket socket;
198
+ socket.bind(QHostAddress::AnyIPv4, port, QUdpSocket::ShareAddress);
199
+
200
+ socket.writeDatagram(data, QHostAddress(host), port);
201
+
202
+ socket.close();
189
203
}
190
204
```
191
205
</details>
@@ -197,26 +211,27 @@ void sendPIDOverUDP(int port) {
197
211
using System;
198
212
using System.Net;
199
213
using System.Net.Sockets;
200
- using System.Text;
201
- using System.Diagnostics;
202
214
203
215
public class Program
204
216
{
205
217
public static void SendPIDOverUDP(int port)
206
218
{
207
- UdpClient udpClient = new UdpClient();
208
- int pid = Process.GetCurrentProcess().Id;
209
- string message = "p" + pid.ToString();
210
- byte[] data = Encoding.UTF8.GetBytes(message);
211
-
212
- IPEndPoint endPoint = new IPEndPoint(IPAddress.Broadcast, port);
213
- udpClient.Send(data, data.Length, endPoint);
214
- udpClient.Close();
215
- }
216
-
217
- public static void Main()
218
- {
219
- SendPIDOverUDP(12345);
219
+ try
220
+ {
221
+ string host = "127.0.0.255";
222
+ string pid = "p" + System.Diagnostics.Process.GetCurrentProcess().Id.ToString();
223
+ byte[] data = System.Text.Encoding.ASCII.GetBytes(pid);
224
+
225
+ using (UdpClient client = new UdpClient())
226
+ {
227
+ client.EnableBroadcast = true;
228
+ client.Send(data, data.Length, new IPEndPoint(IPAddress.Parse(host), port));
229
+ }
230
+ }
231
+ catch (Exception e)
232
+ {
233
+ Console.WriteLine("Exception: " + e.Message);
234
+ }
220
235
}
221
236
}
222
237
```
@@ -226,13 +241,22 @@ public class Program
226
241
227
242
### Python
228
243
``` python
229
- import os
230
244
import socket
245
+ import os
231
246
232
- sock = socket.socket(socket.AF_INET , socket.SOCK_DGRAM )
233
- pid = str (os.getpid())
234
- data = ' p' + pid
235
- sock.sendto(data.encode(' utf-8' ), (' localhost' , 12345 ))
247
+ def send_pid_over_udp (port ):
248
+ try :
249
+ host = ' 127.0.0.255'
250
+ pid = f " p { os.getpid()} "
251
+ data = pid.encode()
252
+
253
+ sock = socket.socket(socket.AF_INET , socket.SOCK_DGRAM )
254
+ sock.setsockopt(socket.SOL_SOCKET , socket.SO_BROADCAST , 1 )
255
+ sock.sendto(data, (host, port))
256
+ sock.close()
257
+
258
+ except Exception as e:
259
+ print (f " Exception: { e} " )
236
260
```
237
261
</details >
238
262
<details >
@@ -242,13 +266,13 @@ sock.sendto(data.encode('utf-8'), ('localhost', 12345))
242
266
``` bash
243
267
#! /bin/bash
244
268
245
- sendPIDOverUDP () {
269
+ send_pid_over_udp () {
246
270
local port=$1
247
- local pid=" p$$ "
248
- echo -n $pid | nc -u -w1 -b 127.0.0.1 $port
249
- }
271
+ local host=" 127.0.0.255"
272
+ local pid=" p$$ " # $$ gives the PID of the current shell process
250
273
251
- sendPIDOverUDP 12345
274
+ echo -n " $pid " | socat - UDP-DATAGRAM:$host :$port ,broadcast
275
+ }
252
276
```
253
277
</details >
254
278
@@ -311,12 +335,16 @@ Or just `./run.sh &` which is recommended.
311
335
312
336
## TODO
313
337
- Redesign the apps.c
314
- - Replace ini with json file
315
338
- Add CPU & RAM usage to the statistics
316
- - Add Telnet console
317
- - Enable remote syslog server reporting
339
+ - Create easy-to-use heartbeat libraries
318
340
- Enable commands over UDP
341
+ - Enable remote syslog server reporting
342
+ - Add periodic reboot feature
319
343
- Add IPC and TCP support
344
+ - Add json support
345
+ - Add remote Telnet console
346
+ - Add config wizard
347
+ - Add multiplatform GUI
320
348
321
349
## :snowman : Author
322
350
Eray Öztürk ([ @diffstorm ] ( https://github.com/diffstorm ) )
0 commit comments