-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathdoc.go
More file actions
276 lines (188 loc) · 11.1 KB
/
doc.go
File metadata and controls
276 lines (188 loc) · 11.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
/*
It is a library that lets you monitor certain activities on your machine, and then sends a heartbeat (explained later)
at a periodic (configurable) time detailing all the activity changes during that time. The activities that you want
to track are monitored by pluggable handlers for those activities and can be added or removed according to
your needs. An example of an activity is MouseCursorActivity, i.e. whether your mouse cursor was moved or not.
Installation
The library can be installed using:
go get -u github.com/prashantgupta24/activity-tracker
Usage
The usage is as following:
heartbeatInterval := 60 //value always in seconds
workerInterval := 5 //seconds
activityTracker := &tracker.Instance{
HeartbeatInterval: heartbeatInterval,
WorkerInterval: workerInterval,
LogLevel: logging.Info,
}
// This starts the tracker for all handlers currently implemented. It gives you a channel on
// which you can listen to for heartbeat objects
heartbeatCh := activityTracker.Start()
//if you only want to track certain handlers, you can use StartWithhandlers
//heartbeatCh := activityTracker.StartWithHandlers(handler.MouseClickHandler(), handler.MouseCursorHandler())
select {
case heartbeat := <-heartbeatCh:
if !heartbeat.WasAnyActivity {
logger.Infof("no activity detected in the last %v seconds", int(heartbeatInterval))
} else {
logger.Infof("activity detected in the last %v seconds.", int(heartbeatInterval))
logger.Infof("Activity type:\n")
for activityType, times := range heartbeat.ActivityMap {
logger.Infof("activityType : %v times: %v\n", activityType, len(times))
}
}
}
Output
The above code created a tracker with all
('Mouse-click', 'Mouse-movement', 'screen-change' and 'machine-sleep') handlers activated.
The heartbeat Interval is set to 60 seconds, i.e. every 60 seconds
I received a heartbeat which mentioned all activities that were captured.
INFO[2019-03-30T15:52:01-07:00] starting activity tracker with 60s heartbeat and 5s worker Interval...
INFO[2019-03-30T15:53:01-07:00] activity detected in the last 60 seconds.
INFO[2019-03-30T15:53:01-07:00] Activity type:
INFO[2019-03-30T15:53:01-07:00] activityType : mouse-click times: 10
INFO[2019-03-30T15:53:01-07:00] activityType : cursor-move times: 12
INFO[2019-03-30T15:53:01-07:00] activityType : screen-change times: 7
INFO[2019-03-30T15:53:01-07:00] activityType : machine-sleep times: 1
INFO[2019-03-30T15:53:01-07:00] activityType : machine-wake times: 1
How it works
There are 2 primary configs required for the tracker to work:
- HeartbeatInterval
The Interval at which you want the heartbeat (in seconds, default 60s)
and
- WorkerInterval
The Interval at which you want the checks to happen within a heartbeat (default 60s).
The activity tracker gives you a heartbeat object every 60 seconds, that is based on the
'HeartbeatInterval'. But there is something else to understand here. In order for the
tracker to know how many times an activity occurred, like how many times you moved the
cursor for example, it needs to query the mouse position every 'x' seconds. That's
where the 'WorkerInterval' comes into play.
The 'WorkerInterval' tells the tracker how frequently to check for an activity within a heartbeat.
It does that by querying the handler associated with that activity. Let's say you want to know
how many times the mouse cursor was moved within 60 seconds. You need to constantly ask the
'mouseCursorHandler' every 'x' seconds to see if the cursor moved. What you want to do is
to start the tracker with the usual 60s 'HeartbeatInterval ', configured with a 'Mouse-cursor'
handler. In this case, you set the 'WorkerInterval' to 5 seconds. The tracker will then keep
asking the mouse cursor handler every 5 seconds to see if there was a movement, and keep
track each time there was a change. At the end of 'HeartbeatInterval', it will construct
the 'heartbeat' with all the changes and send it.
For example, in the output that you saw above, it says 'cursor-move times: 12'. That doesn't
mean the cursor was moved only 12 times. Since the 'WorkerInterval' was 5 seconds in the
example, that means 'cursorHandler' was asked every 5 seconds (i.e. 12 times in 60 seconds)
whether the cursor moved. And it replied that the cursor had indeed moved everytime.
Note : This is applicable only to pull-based handlers(discussed below). For push-based
handlers, 'WorkerInterval' does not matter.
- If you want to know how many 'times' an activity occurred within a heartbeat,
you might want to set the 'WorkerInterval' to a low value, so that it keeps quering the handlers.
- If you are just concerned whether any activity happened within a heartbeat or not,
you can set 'WorkerInterval' to a high number (something around 10-15 seconds should do the
trick). That way, the workers need not be bothered a lot of times within a 'heartbeat'.
Note: If the 'WorkerInterval' and the 'HeartbeatInterval' are set the same, then the
'WorkerInterval' always is started a fraction of a second before the 'HeartbeatInterval'
kicks in. This is done so that when the 'heartbeat' is going to be generated at the end
of 'HeartbeatInterval', the worker should have done its job of querying each of the
handlers before that.
Usecase
Suppose you want to track Activities A, B and C on your machine, and you want to know
how many times they occurred every minute.
You want a report at the end of every minute saying 'Activity A' happened 5 times,
'Activity B' happened 3 times and 'Activity C' happened 2 times.
First, you need to create a 'Handler' for each of those activities. See sections
below on how to create one. The main 'tracker' object will simply ask each of the
handlers every 'WorkerInterval' amout of time whether that activity happened or
not at that moment.
As another example, let's say you want to monitor whether there was any mouse click
on your machine and you want to be notified every 5 minutes. What you do is start the
'Activity Tracker' with just the 'mouse click' handler and 'heartbeat' Interval set
to 5 minutes. The 'Start' function of the library gives you a channel which receives
a 'heartbeat' every 5 minutes, and it has details on whether there was a 'click' in
those 5 minutes, and if yes, the times the click happened.
Components
- Heartbeat struct
It is the data packet sent from the tracker library to the user.
type Heartbeat struct {
WasAnyActivity bool
ActivityMap map[activity.Type][]time.Time //activity type with its times
Time time.Time //heartbeat time
}
'WasAnyActivity' tells if there was any activity within that time frame
If there was, then the 'ActivityMap' will tell you what type of activity it was and
what all times it occurred.
The 'Time' field is the time of the Heartbeat sent (not to be confused with
the activity time, which is the time the activity occurred within the 'heartbeat').
Tracker
The tracker is the main struct for the library. The fields inside it are:
HeartbeatInterval int //the interval at which you want the heartbeat (in seconds, default 60s)
WorkerInterval int //the interval at which you want the checks to happen within a heartbeat (in seconds, default 5s)
LogLevel string //info or debug
LogFormat string //text or json
'HeartbeatInterval'
The Interval at which you want the heartbeat (in seconds, default 60s)
The 'HeartbeatInterval ' value can be set anywhere between 60 seconds - 300 seconds.
Not setting it or setting it to anything other than the allowed range will revert it
to default of 60s.
'WorkerInterval'
The Interval at which you want the checks to happen within a heartbeat (default 60s).
The 'WorkerInterval ' value can be set anywhere between 4 seconds - 60 seconds. It
CANNOT be more than 'HeartbeatInterval' for obvious reasons. Not setting it or setting
it to anything other than the allowed range will revert it to default of 60s.
State
The 'system.State' struct captures the current state of the tracker, and the whole system
in general. It is used by some of the handlers to respond to a certain system state.
It is passed to the handlers when performing the Trigger, so that the handlers can take
an informed decision on whether to get activated or not at that instance.
For example, the 'sleepHandler' changes the state of the system to sleeping, so that
the 'mouseCursorHandler' and 'mouseClickHandler' don't need to do any work while the
system remains in the sleep state.
Note: It also serves as a way of inter-handler communication.
Types of handlers
There are 2 types of handlers:
- Push based
- Pull based
The 'push' based ones are those that automatically push to the 'tracker' object
when an activity happened. Examples are the 'mouseClickHander' and 'machineSleepHandler'.
Whenever a mouse-click/machine-sleep happens, it sends the 'activity' to the 'tracker' object.
The 'pull' based ones are those that the 'tracker' has to ask the handler to know if
there was any activity happening at that moment.
Examples are 'mouseCursorHandler' and 'screenChangeHandler'. The 'asking' is done through
the 'Trigger' function implemented by handlers.
It is up to you to define how to implement the handler. Some make sense to be pull based,
since it is going to be memory intensive to make the mouse cursor movement handler
push-based. It made sense to make it 'pull' based.
New pluggable handlers for activities
Any new type of handler for an activity can be easily added, it just needs to
implement the above 'Handler' interface below:
//Handler interface
Start(*log.Logger, chan *activity.Instance)
Type() activity.Type
Trigger(system.State) //used to activate pull-based handlers
Close()
It also needs to define what 'type' of activity it is going to
track (also add the new 'activity' as well if it's a new activity), that's it! It can
be plugged in with the tracker and then the tracker will include those activity checks
in its heartbeat.
Note: Handlers have a one-to-many relationship with activity, i.e. each Handler can
be associated with one or more activity (That becomes the value returned by handler's 'Type')
On the other hand, each activity should be tracked by only ONE handler (which makes sense).
As a fail-safe, if the tracker is started with more than one handler tracking the same
activity, then only 1 handler will get registered for that activity.
Supported list of activities and their handlers
Currently supported activities are:
MouseCursorMovement Type = "cursor-move"
MouseClick Type = "mouse-click"
ScreenChange Type = "screen-change"
MachineSleep Type = "machine-sleep"
MachineWake Type = "machine-wake"
Corresponding handlers:
mouseCursorHandler
mouseClickHandler
screenChangeHandler
machineSleepHandler
- Mouse click (whether any mouse click happened during the time frame)
- Mouse cursor movement (whether the mouse cursor was moved during the time frame)
- Screen change handler (whether the active window was changed)
- Machine sleep/wake handler (**this is added by default for fail-safe measures**)
Example
Check out the example here : https://github.com/prashantgupta24/activity-tracker/blob/master/example/example.go
*/
package main