1 /******************************************************************************
3 * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
5 * This program is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU General Public License *
7 * as published by the Free Software Foundation; either version 2 *
8 * of the License, or (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the Free Software Foundation *
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
18 ******************************************************************************/
20 #include "db_ido/dbevents.h"
21 #include "db_ido/dbtype.h"
22 #include "db_ido/dbvalue.h"
23 #include "base/convert.h"
24 #include "base/objectlock.h"
25 #include "base/initialize.h"
26 #include "base/dynamictype.h"
27 #include "base/utility.h"
28 #include "remote/endpoint.h"
29 #include "icinga/notification.h"
30 #include "icinga/checkcommand.h"
31 #include "icinga/eventcommand.h"
32 #include "icinga/externalcommandprocessor.h"
33 #include "icinga/compatutility.h"
34 #include "icinga/icingaapplication.h"
35 #include <boost/foreach.hpp>
36 #include <boost/algorithm/string/join.hpp>
38 using namespace icinga;
40 INITIALIZE_ONCE(&DbEvents::StaticInitialize);
42 void DbEvents::StaticInitialize(void)
45 Service::OnCommentAdded.connect(boost::bind(&DbEvents::AddComment, _1, _2));
46 Service::OnCommentRemoved.connect(boost::bind(&DbEvents::RemoveComment, _1, _2));
47 Service::OnDowntimeAdded.connect(boost::bind(&DbEvents::AddDowntime, _1, _2));
48 Service::OnDowntimeRemoved.connect(boost::bind(&DbEvents::RemoveDowntime, _1, _2));
49 Service::OnDowntimeTriggered.connect(boost::bind(&DbEvents::TriggerDowntime, _1, _2));
52 Service::OnCommentAdded.connect(boost::bind(&DbEvents::AddCommentHistory, _1, _2));
53 Service::OnDowntimeAdded.connect(boost::bind(&DbEvents::AddDowntimeHistory, _1, _2));
54 Service::OnAcknowledgementSet.connect(boost::bind(&DbEvents::AddAcknowledgementHistory, _1, _2, _3, _4, _5));
56 Service::OnNotificationSentToAllUsers.connect(bind(&DbEvents::AddNotificationHistory, _1, _2, _3, _4, _5, _6, _7));
58 Service::OnStateChange.connect(boost::bind(&DbEvents::AddStateChangeHistory, _1, _2, _3));
60 Service::OnNewCheckResult.connect(bind(&DbEvents::AddCheckResultLogHistory, _1, _2));
61 Service::OnNotificationSentToUser.connect(bind(&DbEvents::AddNotificationSentLogHistory, _1, _2, _3, _4, _5, _6, _7));
62 Service::OnFlappingChanged.connect(bind(&DbEvents::AddFlappingLogHistory, _1, _2));
63 Service::OnDowntimeTriggered.connect(boost::bind(&DbEvents::AddTriggerDowntimeLogHistory, _1, _2));
64 Service::OnDowntimeRemoved.connect(boost::bind(&DbEvents::AddRemoveDowntimeLogHistory, _1, _2));
66 Service::OnFlappingChanged.connect(bind(&DbEvents::AddFlappingHistory, _1, _2));
67 Service::OnNewCheckResult.connect(bind(&DbEvents::AddServiceCheckHistory, _1, _2));
69 Service::OnEventCommandExecuted.connect(bind(&DbEvents::AddEventHandlerHistory, _1));
71 ExternalCommandProcessor::OnNewExternalCommand.connect(boost::bind(&DbEvents::AddExternalCommandHistory, _1, _2, _3));
75 void DbEvents::AddComments(const Checkable::Ptr& checkable)
77 /* dump all comments */
78 Dictionary::Ptr comments = checkable->GetComments();
80 if (comments->GetLength() > 0)
81 RemoveComments(checkable);
83 ObjectLock olock(comments);
85 BOOST_FOREACH(const Dictionary::Pair& kv, comments) {
86 AddComment(checkable, kv.second);
90 void DbEvents::AddComment(const Checkable::Ptr& checkable, const Comment::Ptr& comment)
92 AddCommentInternal(checkable, comment, false);
95 void DbEvents::AddCommentHistory(const Checkable::Ptr& checkable, const Comment::Ptr& comment)
97 AddCommentInternal(checkable, comment, true);
100 void DbEvents::AddCommentInternal(const Checkable::Ptr& checkable, const Comment::Ptr& comment, bool historical)
103 Log(LogWarning, "db_ido", "comment does not exist. not adding it.");
107 Log(LogDebug, "db_ido", "adding service comment (id = " + Convert::ToString(comment->GetLegacyId()) + ") for '" + checkable->GetName() + "'");
109 /* add the service comment */
110 AddCommentByType(checkable, comment, historical);
113 void DbEvents::AddCommentByType(const DynamicObject::Ptr& object, const Comment::Ptr& comment, bool historical)
115 unsigned long entry_time = static_cast<long>(comment->GetEntryTime());
116 unsigned long entry_time_usec = (comment->GetEntryTime() - entry_time) * 1000 * 1000;
118 Dictionary::Ptr fields1 = make_shared<Dictionary>();
119 fields1->Set("entry_time", DbValue::FromTimestamp(entry_time));
120 fields1->Set("entry_time_usec", entry_time_usec);
121 fields1->Set("entry_type", comment->GetEntryType());
122 fields1->Set("object_id", object);
124 if (object->GetType() == DynamicType::GetByName("Host")) {
125 fields1->Set("comment_type", 2);
126 /* requires idoutils 1.10 schema fix */
127 fields1->Set("internal_comment_id", comment->GetLegacyId());
128 } else if (object->GetType() == DynamicType::GetByName("Service")) {
129 fields1->Set("comment_type", 1);
130 fields1->Set("internal_comment_id", comment->GetLegacyId());
132 Log(LogDebug, "db_ido", "unknown object type for adding comment.");
136 fields1->Set("comment_time", DbValue::FromTimestamp(entry_time)); /* same as entry_time */
137 fields1->Set("author_name", comment->GetAuthor());
138 fields1->Set("comment_data", comment->GetText());
139 fields1->Set("is_persistent", 1);
140 fields1->Set("comment_source", 1); /* external */
141 fields1->Set("expires", (comment->GetExpireTime() > 0) ? 1 : 0);
142 fields1->Set("expiration_time", DbValue::FromTimestamp(comment->GetExpireTime()));
143 fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
145 String node = IcingaApplication::GetInstance()->GetNodeName();
147 Endpoint::Ptr endpoint = Endpoint::GetByName(node);
149 fields1->Set("endpoint_object_id", endpoint);
153 query1.Table = "comments";
155 query1.Table = "commenthistory";
157 query1.Type = DbQueryInsert;
158 query1.Category = DbCatComment;
159 query1.Fields = fields1;
160 DbObject::OnQuery(query1);
163 void DbEvents::RemoveComments(const Checkable::Ptr& checkable)
165 Log(LogDebug, "db_ido", "removing service comments for '" + checkable->GetName() + "'");
168 query1.Table = "comments";
169 query1.Type = DbQueryDelete;
170 query1.Category = DbCatComment;
171 query1.WhereCriteria = make_shared<Dictionary>();
172 query1.WhereCriteria->Set("object_id", checkable);
173 DbObject::OnQuery(query1);
176 void DbEvents::RemoveComment(const Checkable::Ptr& checkable, const Comment::Ptr& comment)
179 Log(LogWarning, "db_ido", "comment does not exist. not deleting it.");
183 Log(LogDebug, "db_ido", "removing service comment (id = " + Convert::ToString(comment->GetLegacyId()) + ") for '" + checkable->GetName() + "'");
187 query1.Table = "comments";
188 query1.Type = DbQueryDelete;
189 query1.Category = DbCatComment;
190 query1.WhereCriteria = make_shared<Dictionary>();
191 query1.WhereCriteria->Set("object_id", checkable);
192 query1.WhereCriteria->Set("internal_comment_id", comment->GetLegacyId());
193 DbObject::OnQuery(query1);
195 /* History - update deletion time for service/host */
196 unsigned long entry_time = static_cast<long>(comment->GetEntryTime());
198 double now = Utility::GetTime();
199 std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
202 query2.Table = "commenthistory";
203 query2.Type = DbQueryUpdate;
204 query2.Category = DbCatComment;
206 Dictionary::Ptr fields2 = make_shared<Dictionary>();
207 fields2->Set("deletion_time", DbValue::FromTimestamp(time_bag.first));
208 fields2->Set("deletion_time_usec", time_bag.second);
209 query2.Fields = fields2;
211 query2.WhereCriteria = make_shared<Dictionary>();
212 query2.WhereCriteria->Set("internal_comment_id", comment->GetLegacyId());
213 query2.WhereCriteria->Set("comment_time", DbValue::FromTimestamp(entry_time));
214 query2.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
216 DbObject::OnQuery(query2);
220 void DbEvents::AddDowntimes(const Checkable::Ptr& checkable)
222 /* dump all downtimes */
223 Dictionary::Ptr downtimes = checkable->GetDowntimes();
225 if (downtimes->GetLength() > 0)
226 RemoveDowntimes(checkable);
228 ObjectLock olock(downtimes);
230 BOOST_FOREACH(const Dictionary::Pair& kv, downtimes) {
231 AddDowntime(checkable, kv.second);
235 void DbEvents::AddDowntime(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime)
237 AddDowntimeInternal(checkable, downtime, false);
240 void DbEvents::AddDowntimeHistory(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime)
242 AddDowntimeInternal(checkable, downtime, true);
245 void DbEvents::AddDowntimeInternal(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime, bool historical)
248 Log(LogWarning, "db_ido", "downtime does not exist. not adding it.");
252 Log(LogDebug, "db_ido", "adding service downtime (id = " + Convert::ToString(downtime->GetLegacyId()) + ") for '" + checkable->GetName() + "'");
254 /* add the downtime */
255 AddDowntimeByType(checkable, downtime, historical);}
257 void DbEvents::AddDowntimeByType(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime, bool historical)
259 Dictionary::Ptr fields1 = make_shared<Dictionary>();
260 fields1->Set("entry_time", DbValue::FromTimestamp(downtime->GetEntryTime()));
261 fields1->Set("object_id", checkable);
263 if (checkable->GetType() == DynamicType::GetByName("Host")) {
264 fields1->Set("downtime_type", 2);
265 /* requires idoutils 1.10 schema fix */
266 fields1->Set("internal_downtime_id", downtime->GetLegacyId());
267 } else if (checkable->GetType() == DynamicType::GetByName("Service")) {
268 fields1->Set("downtime_type", 1);
269 fields1->Set("internal_downtime_id", downtime->GetLegacyId());
271 Log(LogDebug, "db_ido", "unknown object type for adding downtime.");
275 fields1->Set("author_name", downtime->GetAuthor());
276 fields1->Set("comment_data", downtime->GetComment());
277 fields1->Set("triggered_by_id", Service::GetDowntimeByID(downtime->GetTriggeredBy()));
278 fields1->Set("is_fixed", downtime->GetFixed());
279 fields1->Set("duration", downtime->GetDuration());
280 fields1->Set("scheduled_start_time", DbValue::FromTimestamp(downtime->GetStartTime()));
281 fields1->Set("scheduled_end_time", DbValue::FromTimestamp(downtime->GetEndTime()));
282 fields1->Set("was_started", Empty);
283 fields1->Set("actual_start_time", Empty);
284 fields1->Set("actual_start_time_usec", Empty);
285 fields1->Set("is_in_effect", Empty);
286 fields1->Set("trigger_time", DbValue::FromTimestamp(downtime->GetTriggerTime()));
287 fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
289 String node = IcingaApplication::GetInstance()->GetNodeName();
291 Endpoint::Ptr endpoint = Endpoint::GetByName(node);
293 fields1->Set("endpoint_object_id", endpoint);
298 query1.Table = "scheduleddowntime";
300 query1.Table = "downtimehistory";
302 query1.Type = DbQueryInsert;
303 query1.Category = DbCatDowntime;
304 query1.Fields = fields1;
305 DbObject::OnQuery(query1);
308 void DbEvents::RemoveDowntimes(const Checkable::Ptr& checkable)
310 Log(LogDebug, "db_ido", "removing service downtimes for '" + checkable->GetName() + "'");
313 query1.Table = "scheduleddowntime";
314 query1.Type = DbQueryDelete;
315 query1.Category = DbCatDowntime;
316 query1.WhereCriteria = make_shared<Dictionary>();
317 query1.WhereCriteria->Set("object_id", checkable);
318 DbObject::OnQuery(query1);
321 void DbEvents::RemoveDowntime(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime)
324 Log(LogWarning, "db_ido", "downtime does not exist. not adding it.");
328 Log(LogDebug, "db_ido", "removing service downtime (id = " + Convert::ToString(downtime->GetLegacyId()) + ") for '" + checkable->GetName() + "'");
332 query1.Table = "scheduleddowntime";
333 query1.Type = DbQueryDelete;
334 query1.Category = DbCatDowntime;
335 query1.WhereCriteria = make_shared<Dictionary>();
336 query1.WhereCriteria->Set("object_id", checkable);
337 query1.WhereCriteria->Set("internal_downtime_id", downtime->GetLegacyId());
338 DbObject::OnQuery(query1);
340 /* History - update actual_end_time, was_cancelled for service (and host in case) */
341 double now = Utility::GetTime();
342 std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
345 query3.Table = "downtimehistory";
346 query3.Type = DbQueryUpdate;
347 query3.Category = DbCatDowntime;
349 Dictionary::Ptr fields3 = make_shared<Dictionary>();
350 fields3->Set("was_cancelled", downtime->GetWasCancelled() ? 1 : 0);
351 fields3->Set("actual_end_time", DbValue::FromTimestamp(time_bag.first));
352 fields3->Set("actual_end_time_usec", time_bag.second);
353 query3.Fields = fields3;
355 query3.WhereCriteria = make_shared<Dictionary>();
356 query3.WhereCriteria->Set("internal_downtime_id", downtime->GetLegacyId());
357 query3.WhereCriteria->Set("entry_time", DbValue::FromTimestamp(downtime->GetEntryTime()));
358 query3.WhereCriteria->Set("scheduled_start_time", DbValue::FromTimestamp(downtime->GetStartTime()));
359 query3.WhereCriteria->Set("scheduled_end_time", DbValue::FromTimestamp(downtime->GetEndTime()));
360 query3.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
362 DbObject::OnQuery(query3);
365 void DbEvents::TriggerDowntime(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime)
368 Log(LogWarning, "db_ido", "downtime does not exist. not updating it.");
372 Log(LogDebug, "db_ido", "updating triggered service downtime (id = " + Convert::ToString(downtime->GetLegacyId()) + ") for '" + checkable->GetName() + "'");
374 double now = Utility::GetTime();
375 std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
379 query1.Table = "scheduleddowntime";
380 query1.Type = DbQueryUpdate;
381 query1.Category = DbCatDowntime;
383 Dictionary::Ptr fields1 = make_shared<Dictionary>();
384 fields1->Set("was_started", 1);
385 fields1->Set("actual_start_time", DbValue::FromTimestamp(time_bag.first));
386 fields1->Set("actual_start_time_usec", time_bag.second);
387 fields1->Set("is_in_effect", 1);
388 fields1->Set("trigger_time", DbValue::FromTimestamp(downtime->GetTriggerTime()));
389 fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
391 query1.WhereCriteria = make_shared<Dictionary>();
392 query1.WhereCriteria->Set("object_id", checkable);
393 query1.WhereCriteria->Set("internal_downtime_id", downtime->GetLegacyId());
395 query1.Fields = fields1;
396 DbObject::OnQuery(query1);
398 /* History - downtime was started for service (and host in case) */
400 query3.Table = "downtimehistory";
401 query3.Type = DbQueryUpdate;
402 query3.Category = DbCatDowntime;
404 Dictionary::Ptr fields3 = make_shared<Dictionary>();
405 fields3->Set("was_started", 1);
406 fields3->Set("is_in_effect", 1);
407 fields3->Set("actual_start_time", DbValue::FromTimestamp(time_bag.first));
408 fields3->Set("actual_start_time_usec", time_bag.second);
409 fields3->Set("trigger_time", DbValue::FromTimestamp(downtime->GetTriggerTime()));
410 query3.Fields = fields3;
412 query3.WhereCriteria = make_shared<Dictionary>();
413 query3.WhereCriteria->Set("internal_downtime_id", downtime->GetLegacyId());
414 query3.WhereCriteria->Set("entry_time", DbValue::FromTimestamp(downtime->GetEntryTime()));
415 query3.WhereCriteria->Set("scheduled_start_time", DbValue::FromTimestamp(downtime->GetStartTime()));
416 query3.WhereCriteria->Set("scheduled_end_time", DbValue::FromTimestamp(downtime->GetEndTime()));
417 query3.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
419 DbObject::OnQuery(query3);
422 /* acknowledgements */
423 void DbEvents::AddAcknowledgementHistory(const Checkable::Ptr& checkable, const String& author, const String& comment,
424 AcknowledgementType type, double expiry)
426 Log(LogDebug, "db_ido", "add acknowledgement history for '" + checkable->GetName() + "'");
428 double now = Utility::GetTime();
429 std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
431 unsigned long end_time = static_cast<long>(expiry);
434 query1.Table = "acknowledgements";
435 query1.Type = DbQueryInsert;
436 query1.Category = DbCatAcknowledgement;
439 Service::Ptr service;
440 tie(host, service) = GetHostService(checkable);
442 Dictionary::Ptr fields1 = make_shared<Dictionary>();
443 fields1->Set("entry_time", DbValue::FromTimestamp(time_bag.first));
444 fields1->Set("entry_time_usec", time_bag.second);
445 fields1->Set("acknowledgement_type", type);
446 fields1->Set("object_id", checkable);
447 fields1->Set("state", service ? service->GetState() : host->GetState());
448 fields1->Set("author_name", author);
449 fields1->Set("comment_data", comment);
450 fields1->Set("is_sticky", type == AcknowledgementSticky ? 1 : 0);
451 fields1->Set("end_time", DbValue::FromTimestamp(end_time));
452 fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
454 String node = IcingaApplication::GetInstance()->GetNodeName();
456 Endpoint::Ptr endpoint = Endpoint::GetByName(node);
458 fields1->Set("endpoint_object_id", endpoint);
460 query1.Fields = fields1;
461 DbObject::OnQuery(query1);
465 void DbEvents::AddNotificationHistory(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const std::set<User::Ptr>& users, NotificationType type,
466 const CheckResult::Ptr& cr, const String& author, const String& text)
468 Log(LogDebug, "db_ido", "add notification history for '" + checkable->GetName() + "'");
470 /* start and end happen at the same time */
471 double now = Utility::GetTime();
472 std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
475 query1.Table = "notifications";
476 query1.Type = DbQueryInsert;
477 query1.Category = DbCatNotification;
478 /* store the object ptr for caching the insert id for this object */
479 query1.NotificationObject = notification;
482 Service::Ptr service;
483 tie(host, service) = GetHostService(checkable);
485 Dictionary::Ptr fields1 = make_shared<Dictionary>();
486 fields1->Set("notification_type", 1); /* service */
487 fields1->Set("notification_reason", CompatUtility::MapNotificationReasonType(type));
488 fields1->Set("object_id", checkable);
489 fields1->Set("start_time", DbValue::FromTimestamp(time_bag.first));
490 fields1->Set("start_time_usec", time_bag.second);
491 fields1->Set("end_time", DbValue::FromTimestamp(time_bag.first));
492 fields1->Set("end_time_usec", time_bag.second);
493 fields1->Set("state", service ? service->GetState() : host->GetState());
496 fields1->Set("output", CompatUtility::GetCheckResultOutput(cr));
497 fields1->Set("long_output", CompatUtility::GetCheckResultLongOutput(cr));
500 fields1->Set("escalated", 0);
501 fields1->Set("contacts_notified", static_cast<long>(users.size()));
502 fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
504 String node = IcingaApplication::GetInstance()->GetNodeName();
506 Endpoint::Ptr endpoint = Endpoint::GetByName(node);
508 fields1->Set("endpoint_object_id", endpoint);
510 query1.Fields = fields1;
511 DbObject::OnQuery(query1);
514 query2.Table = "contactnotifications";
515 query2.Type = DbQueryInsert;
516 query2.Category = DbCatNotification;
519 BOOST_FOREACH(const User::Ptr& user, users) {
520 Log(LogDebug, "db_ido", "add contact notification history for service '" + checkable->GetName() + "' and user '" + user->GetName() + "'.");
522 Dictionary::Ptr fields2 = make_shared<Dictionary>();
523 fields2->Set("contact_object_id", user);
524 fields2->Set("start_time", DbValue::FromTimestamp(time_bag.first));
525 fields2->Set("start_time_usec", time_bag.second);
526 fields2->Set("end_time", DbValue::FromTimestamp(time_bag.first));
527 fields2->Set("end_time_usec", time_bag.second);
529 fields2->Set("notification_id", notification); /* DbConnection class fills in real ID from notification insert id cache */
530 fields2->Set("instance_id", 0); /* DbConnection class fills in real ID */
532 query2.Fields = fields2;
533 DbObject::OnQuery(query2);
538 void DbEvents::AddStateChangeHistory(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, StateType type)
540 Log(LogDebug, "db_ido", "add state change history for '" + checkable->GetName() + "'");
542 double now = Utility::GetTime();
543 std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
546 query1.Table = "statehistory";
547 query1.Type = DbQueryInsert;
548 query1.Category = DbCatStateHistory;
551 Service::Ptr service;
552 tie(host, service) = GetHostService(checkable);
554 Dictionary::Ptr fields1 = make_shared<Dictionary>();
555 fields1->Set("state_time", DbValue::FromTimestamp(time_bag.first));
556 fields1->Set("state_time_usec", time_bag.second);
557 fields1->Set("object_id", checkable);
558 fields1->Set("state_change", 1); /* service */
559 fields1->Set("state", service ? service->GetState() : host->GetState());
560 fields1->Set("state_type", checkable->GetStateType());
561 fields1->Set("current_check_attempt", checkable->GetCheckAttempt());
562 fields1->Set("max_check_attempts", checkable->GetMaxCheckAttempts());
565 fields1->Set("last_state", service->GetLastState());
566 fields1->Set("last_hard_state", service->GetLastHardState());
568 fields1->Set("last_state", host->GetLastState());
569 fields1->Set("last_hard_state", host->GetLastHardState());
573 fields1->Set("output", CompatUtility::GetCheckResultOutput(cr));
574 fields1->Set("long_output", CompatUtility::GetCheckResultLongOutput(cr));
575 fields1->Set("check_source", cr->GetCheckSource());
578 fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
580 String node = IcingaApplication::GetInstance()->GetNodeName();
582 Endpoint::Ptr endpoint = Endpoint::GetByName(node);
584 fields1->Set("endpoint_object_id", endpoint);
586 query1.Fields = fields1;
587 DbObject::OnQuery(query1);
591 void DbEvents::AddCheckResultLogHistory(const Checkable::Ptr& checkable, const CheckResult::Ptr &cr)
593 Dictionary::Ptr vars_after = cr->GetVarsAfter();
595 long state_after = vars_after->Get("state");
596 long stateType_after = vars_after->Get("state_type");
597 long attempt_after = vars_after->Get("attempt");
598 bool reachable_after = vars_after->Get("reachable");
599 bool host_reachable_after = vars_after->Get("host_reachable");
601 Dictionary::Ptr vars_before = cr->GetVarsBefore();
604 long state_before = vars_before->Get("state");
605 long stateType_before = vars_before->Get("state_type");
606 long attempt_before = vars_before->Get("attempt");
607 bool reachable_before = vars_before->Get("reachable");
609 if (state_before == state_after && stateType_before == stateType_after &&
610 attempt_before == attempt_after && reachable_before == reachable_after)
611 return; /* Nothing changed, ignore this checkresult. */
618 output = CompatUtility::GetCheckResultOutput(cr);
621 Service::Ptr service;
622 tie(host, service) = GetHostService(checkable);
624 std::ostringstream msgbuf;
627 msgbuf << "SERVICE ALERT: "
628 << host->GetName() << ";"
629 << service->GetShortName() << ";"
630 << Service::StateToString(static_cast<ServiceState>(state_after)) << ";"
631 << Service::StateTypeToString(static_cast<StateType>(stateType_after)) << ";"
632 << attempt_after << ";"
636 switch (service->GetState()) {
638 type = LogEntryTypeServiceOk;
641 type = LogEntryTypeServiceUnknown;
644 type = LogEntryTypeServiceWarning;
647 type = LogEntryTypeServiceCritical;
650 Log(LogCritical, "db_ido", "Unknown service state: " + Convert::ToString(state_after));
654 msgbuf << "HOST ALERT: "
655 << host->GetName() << ";"
656 << Host::StateToString(Host::CalculateState(static_cast<ServiceState>(state_after), host_reachable_after)) << ";"
657 << Service::StateTypeToString(static_cast<StateType>(stateType_after)) << ";"
658 << attempt_after << ";"
662 switch (host->GetState()) {
664 type = LogEntryTypeHostUp;
667 type = LogEntryTypeHostDown;
669 case HostUnreachable:
670 type = LogEntryTypeHostUnreachable;
673 Log(LogCritical, "db_ido", "Unknown host state: " + Convert::ToString(state_after));
679 AddLogHistory(checkable, msgbuf.str(), type);
682 void DbEvents::AddTriggerDowntimeLogHistory(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime)
688 Service::Ptr service;
689 tie(host, service) = GetHostService(checkable);
691 std::ostringstream msgbuf;
694 msgbuf << "SERVICE DOWNTIME ALERT: "
695 << host->GetName() << ";"
696 << service->GetShortName() << ";"
698 << "Service has entered a period of scheduled downtime."
701 msgbuf << "HOST DOWNTIME ALERT: "
702 << host->GetName() << ";"
704 << "Service has entered a period of scheduled downtime."
708 AddLogHistory(checkable, msgbuf.str(), LogEntryTypeInfoMessage);
711 void DbEvents::AddRemoveDowntimeLogHistory(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime)
716 String downtime_output;
717 String downtime_state_str;
719 if (downtime->GetWasCancelled()) {
720 downtime_output = "Scheduled downtime for service has been cancelled.";
721 downtime_state_str = "CANCELLED";
723 downtime_output = "Service has exited from a period of scheduled downtime.";
724 downtime_state_str = "STOPPED";
728 Service::Ptr service;
729 tie(host, service) = GetHostService(checkable);
731 std::ostringstream msgbuf;
734 msgbuf << "SERVICE DOWNTIME ALERT: "
735 << host->GetName() << ";"
736 << service->GetShortName() << ";"
737 << downtime_state_str << "; "
741 msgbuf << "HOST DOWNTIME ALERT: "
742 << host->GetName() << ";"
743 << downtime_state_str << "; "
748 AddLogHistory(service, msgbuf.str(), LogEntryTypeInfoMessage);
751 void DbEvents::AddNotificationSentLogHistory(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const User::Ptr& user,
752 NotificationType notification_type, const CheckResult::Ptr& cr,
753 const String& author, const String& comment_text)
755 CheckCommand::Ptr commandObj = checkable->GetCheckCommand();
757 String check_command = "";
759 check_command = commandObj->GetName();
761 String notification_type_str = Notification::NotificationTypeToString(notification_type);
763 String author_comment = "";
764 if (notification_type == NotificationCustom || notification_type == NotificationAcknowledgement) {
765 author_comment = ";" + author + ";" + comment_text;
774 output = CompatUtility::GetCheckResultOutput(cr);
777 Service::Ptr service;
778 tie(host, service) = GetHostService(checkable);
780 std::ostringstream msgbuf;
783 msgbuf << "SERVICE NOTIFICATION: "
784 << user->GetName() << ";"
785 << host->GetName() << ";"
786 << service->GetShortName() << ";"
787 << notification_type_str << " "
788 << "(" << Service::StateToString(service->GetState()) << ");"
789 << check_command << ";"
790 << output << author_comment
793 msgbuf << "HOST NOTIFICATION: "
794 << user->GetName() << ";"
795 << host->GetName() << ";"
796 << notification_type_str << " "
797 << "(" << Host::StateToString(host->GetState()) << ");"
798 << check_command << ";"
799 << output << author_comment
803 AddLogHistory(service, msgbuf.str(), LogEntryTypeHostNotification);
806 void DbEvents::AddFlappingLogHistory(const Checkable::Ptr& checkable, FlappingState flapping_state)
808 String flapping_state_str;
809 String flapping_output;
811 switch (flapping_state) {
812 case FlappingStarted:
813 flapping_output = "Service appears to have started flapping (" + Convert::ToString(checkable->GetFlappingCurrent()) + "% change >= " + Convert::ToString(checkable->GetFlappingThreshold()) + "% threshold)";
814 flapping_state_str = "STARTED";
816 case FlappingStopped:
817 flapping_output = "Service appears to have stopped flapping (" + Convert::ToString(checkable->GetFlappingCurrent()) + "% change < " + Convert::ToString(checkable->GetFlappingThreshold()) + "% threshold)";
818 flapping_state_str = "STOPPED";
820 case FlappingDisabled:
821 flapping_output = "Flap detection has been disabled";
822 flapping_state_str = "DISABLED";
825 Log(LogCritical, "db_ido", "Unknown flapping state: " + Convert::ToString(flapping_state));
830 Service::Ptr service;
831 tie(host, service) = GetHostService(checkable);
833 std::ostringstream msgbuf;
836 msgbuf << "SERVICE FLAPPING ALERT: "
837 << host->GetName() << ";"
838 << service->GetShortName() << ";"
839 << flapping_state_str << "; "
843 msgbuf << "HOST FLAPPING ALERT: "
844 << host->GetName() << ";"
845 << flapping_state_str << "; "
850 AddLogHistory(service, msgbuf.str(), LogEntryTypeInfoMessage);
853 void DbEvents::AddLogHistory(const Checkable::Ptr& checkable, String buffer, LogEntryType type)
855 Log(LogDebug, "db_ido", "add log entry history for '" + checkable->GetName() + "'");
857 double now = Utility::GetTime();
858 std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
861 query1.Table = "logentries";
862 query1.Type = DbQueryInsert;
863 query1.Category = DbCatLog;
865 Dictionary::Ptr fields1 = make_shared<Dictionary>();
866 fields1->Set("logentry_time", DbValue::FromTimestamp(time_bag.first));
867 fields1->Set("entry_time", DbValue::FromTimestamp(time_bag.first));
868 fields1->Set("entry_time_usec", time_bag.second);
869 fields1->Set("object_id", checkable); // added in 1.10 see #4754
870 fields1->Set("logentry_type", type);
871 fields1->Set("logentry_data", buffer);
873 fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
875 String node = IcingaApplication::GetInstance()->GetNodeName();
877 Endpoint::Ptr endpoint = Endpoint::GetByName(node);
879 fields1->Set("endpoint_object_id", endpoint);
881 query1.Fields = fields1;
882 DbObject::OnQuery(query1);
885 /* flappinghistory */
886 void DbEvents::AddFlappingHistory(const Checkable::Ptr& checkable, FlappingState flapping_state)
888 Log(LogDebug, "db_ido", "add flapping history for '" + checkable->GetName() + "'");
890 double now = Utility::GetTime();
891 std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
894 query1.Table = "flappinghistory";
895 query1.Type = DbQueryInsert;
896 query1.Category = DbCatFlapping;
898 Dictionary::Ptr fields1 = make_shared<Dictionary>();
900 fields1->Set("event_time", DbValue::FromTimestamp(time_bag.first));
901 fields1->Set("event_time_usec", time_bag.second);
903 switch (flapping_state) {
904 case FlappingStarted:
905 fields1->Set("event_type", 1000);
907 case FlappingStopped:
908 fields1->Set("event_type", 1001);
909 fields1->Set("reason_type", 1);
911 case FlappingDisabled:
912 fields1->Set("event_type", 1001);
913 fields1->Set("reason_type", 2);
916 Log(LogDebug, "db_ido", "Unhandled flapping state: " + Convert::ToString(flapping_state));
921 Service::Ptr service;
922 tie(host, service) = GetHostService(checkable);
924 fields1->Set("flapping_type", service ? 1 : 0);
925 fields1->Set("object_id", checkable);
926 fields1->Set("percent_state_change", checkable->GetFlappingCurrent());
927 fields1->Set("low_threshold", checkable->GetFlappingThreshold());
928 fields1->Set("high_threshold", checkable->GetFlappingThreshold());
930 fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
932 String node = IcingaApplication::GetInstance()->GetNodeName();
934 Endpoint::Ptr endpoint = Endpoint::GetByName(node);
936 fields1->Set("endpoint_object_id", endpoint);
938 query1.Fields = fields1;
939 DbObject::OnQuery(query1);
943 void DbEvents::AddServiceCheckHistory(const Checkable::Ptr& checkable, const CheckResult::Ptr &cr)
948 Log(LogDebug, "db_ido", "add service check history for '" + checkable->GetName() + "'");
951 Service::Ptr service;
952 tie(host, service) = GetHostService(checkable);
954 std::ostringstream msgbuf;
957 query1.Table = service ? "servicechecks" : "hostchecks";
958 query1.Type = DbQueryInsert;
959 query1.Category = DbCatCheck;
961 Dictionary::Ptr fields1 = make_shared<Dictionary>();
962 double execution_time = Service::CalculateExecutionTime(cr);
964 fields1->Set("check_type", CompatUtility::GetCheckableCheckType(checkable));
965 fields1->Set("current_check_attempt", checkable->GetCheckAttempt());
966 fields1->Set("max_check_attempts", checkable->GetMaxCheckAttempts());
967 fields1->Set("state_type", checkable->GetStateType());
969 double now = Utility::GetTime();
970 std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
972 double end = now + execution_time;
973 std::pair<unsigned long, unsigned long> time_bag_end = CompatUtility::ConvertTimestamp(end);
975 fields1->Set("start_time", DbValue::FromTimestamp(time_bag.first));
976 fields1->Set("start_time_usec", time_bag.second);
977 fields1->Set("end_time", DbValue::FromTimestamp(time_bag_end.first));
978 fields1->Set("end_time_usec", time_bag_end.second);
979 fields1->Set("command_object_id", checkable->GetCheckCommand());
980 fields1->Set("command_args", Empty);
981 fields1->Set("command_line", cr->GetCommand());
982 fields1->Set("execution_time", Convert::ToString(execution_time));
983 fields1->Set("latency", Convert::ToString(Service::CalculateLatency(cr)));
984 fields1->Set("return_code", cr->GetExitStatus());
985 fields1->Set("output", CompatUtility::GetCheckResultOutput(cr));
986 fields1->Set("long_output", CompatUtility::GetCheckResultLongOutput(cr));
987 fields1->Set("perfdata", CompatUtility::GetCheckResultPerfdata(cr));
989 fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
992 fields1->Set("service_object_id", service);
993 fields1->Set("state", service->GetState());
995 fields1->Set("host_object_id", host);
996 fields1->Set("state", host->GetState());
999 String node = IcingaApplication::GetInstance()->GetNodeName();
1001 Endpoint::Ptr endpoint = Endpoint::GetByName(node);
1003 fields1->Set("endpoint_object_id", endpoint);
1005 query1.Fields = fields1;
1006 DbObject::OnQuery(query1);
1010 void DbEvents::AddEventHandlerHistory(const Checkable::Ptr& checkable)
1012 Log(LogDebug, "db_ido", "add eventhandler history for '" + checkable->GetName() + "'");
1014 double now = Utility::GetTime();
1015 std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
1018 query1.Table = "eventhandlers";
1019 query1.Type = DbQueryInsert;
1020 query1.Category = DbCatEventHandler;
1022 Dictionary::Ptr fields1 = make_shared<Dictionary>();
1025 Service::Ptr service;
1026 tie(host, service) = GetHostService(checkable);
1028 fields1->Set("eventhandler_type", service ? 1 : 0);
1029 fields1->Set("object_id", checkable);
1030 fields1->Set("state", service ? service->GetState() : host->GetState());
1031 fields1->Set("state_type", checkable->GetStateType());
1033 fields1->Set("start_time", DbValue::FromTimestamp(time_bag.first));
1034 fields1->Set("start_time_usec", time_bag.second);
1035 fields1->Set("end_time", DbValue::FromTimestamp(time_bag.first));
1036 fields1->Set("end_time_usec", time_bag.second);
1037 fields1->Set("command_object_id", checkable->GetEventCommand());
1039 fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
1041 String node = IcingaApplication::GetInstance()->GetNodeName();
1043 Endpoint::Ptr endpoint = Endpoint::GetByName(node);
1045 fields1->Set("endpoint_object_id", endpoint);
1047 query1.Fields = fields1;
1048 DbObject::OnQuery(query1);
1051 /* externalcommands */
1052 void DbEvents::AddExternalCommandHistory(double time, const String& command, const std::vector<String>& arguments)
1054 Log(LogDebug, "db_ido", "add external command history");
1057 query1.Table = "externalcommands";
1058 query1.Type = DbQueryInsert;
1059 query1.Category = DbCatExternalCommand;
1061 Dictionary::Ptr fields1 = make_shared<Dictionary>();
1063 fields1->Set("entry_time", DbValue::FromTimestamp(static_cast<long>(time)));
1064 fields1->Set("command_type", CompatUtility::MapExternalCommandType(command));
1065 fields1->Set("command_name", command);
1066 fields1->Set("command_args", boost::algorithm::join(arguments, ";"));
1068 fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
1070 String node = IcingaApplication::GetInstance()->GetNodeName();
1072 Endpoint::Ptr endpoint = Endpoint::GetByName(node);
1074 fields1->Set("endpoint_object_id", endpoint);
1076 query1.Fields = fields1;
1077 DbObject::OnQuery(query1);