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");
600 Dictionary::Ptr vars_before = cr->GetVarsBefore();
603 long state_before = vars_before->Get("state");
604 long stateType_before = vars_before->Get("state_type");
605 long attempt_before = vars_before->Get("attempt");
606 bool reachable_before = vars_before->Get("reachable");
608 if (state_before == state_after && stateType_before == stateType_after &&
609 attempt_before == attempt_after && reachable_before == reachable_after)
610 return; /* Nothing changed, ignore this checkresult. */
617 output = CompatUtility::GetCheckResultOutput(cr);
620 Service::Ptr service;
621 tie(host, service) = GetHostService(checkable);
623 std::ostringstream msgbuf;
626 msgbuf << "SERVICE ALERT: "
627 << host->GetName() << ";"
628 << service->GetShortName() << ";"
629 << Service::StateToString(static_cast<ServiceState>(state_after)) << ";"
630 << Service::StateTypeToString(static_cast<StateType>(stateType_after)) << ";"
631 << attempt_after << ";"
635 switch (service->GetState()) {
637 type = LogEntryTypeServiceOk;
640 type = LogEntryTypeServiceUnknown;
643 type = LogEntryTypeServiceWarning;
646 type = LogEntryTypeServiceCritical;
649 Log(LogCritical, "db_ido", "Unknown service state: " + Convert::ToString(state_after));
653 String state = Host::StateToString(Host::CalculateState(static_cast<ServiceState>(state_after)));
655 if (!reachable_after)
656 state = "UNREACHABLE";
658 msgbuf << "HOST ALERT: "
659 << host->GetName() << ";"
661 << Service::StateTypeToString(static_cast<StateType>(stateType_after)) << ";"
662 << attempt_after << ";"
666 switch (host->GetState()) {
668 type = LogEntryTypeHostUp;
671 type = LogEntryTypeHostDown;
674 Log(LogCritical, "db_ido", "Unknown host state: " + Convert::ToString(state_after));
678 if (!reachable_after)
679 type = LogEntryTypeHostUnreachable;
682 AddLogHistory(checkable, msgbuf.str(), type);
685 void DbEvents::AddTriggerDowntimeLogHistory(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime)
691 Service::Ptr service;
692 tie(host, service) = GetHostService(checkable);
694 std::ostringstream msgbuf;
697 msgbuf << "SERVICE DOWNTIME ALERT: "
698 << host->GetName() << ";"
699 << service->GetShortName() << ";"
701 << "Service has entered a period of scheduled downtime."
704 msgbuf << "HOST DOWNTIME ALERT: "
705 << host->GetName() << ";"
707 << "Service has entered a period of scheduled downtime."
711 AddLogHistory(checkable, msgbuf.str(), LogEntryTypeInfoMessage);
714 void DbEvents::AddRemoveDowntimeLogHistory(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime)
719 String downtime_output;
720 String downtime_state_str;
722 if (downtime->GetWasCancelled()) {
723 downtime_output = "Scheduled downtime for service has been cancelled.";
724 downtime_state_str = "CANCELLED";
726 downtime_output = "Service has exited from a period of scheduled downtime.";
727 downtime_state_str = "STOPPED";
731 Service::Ptr service;
732 tie(host, service) = GetHostService(checkable);
734 std::ostringstream msgbuf;
737 msgbuf << "SERVICE DOWNTIME ALERT: "
738 << host->GetName() << ";"
739 << service->GetShortName() << ";"
740 << downtime_state_str << "; "
744 msgbuf << "HOST DOWNTIME ALERT: "
745 << host->GetName() << ";"
746 << downtime_state_str << "; "
751 AddLogHistory(checkable, msgbuf.str(), LogEntryTypeInfoMessage);
754 void DbEvents::AddNotificationSentLogHistory(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const User::Ptr& user,
755 NotificationType notification_type, const CheckResult::Ptr& cr,
756 const String& author, const String& comment_text)
758 CheckCommand::Ptr commandObj = checkable->GetCheckCommand();
760 String check_command = "";
762 check_command = commandObj->GetName();
764 String notification_type_str = Notification::NotificationTypeToString(notification_type);
766 String author_comment = "";
767 if (notification_type == NotificationCustom || notification_type == NotificationAcknowledgement) {
768 author_comment = ";" + author + ";" + comment_text;
777 output = CompatUtility::GetCheckResultOutput(cr);
780 Service::Ptr service;
781 tie(host, service) = GetHostService(checkable);
783 std::ostringstream msgbuf;
786 msgbuf << "SERVICE NOTIFICATION: "
787 << user->GetName() << ";"
788 << host->GetName() << ";"
789 << service->GetShortName() << ";"
790 << notification_type_str << " "
791 << "(" << Service::StateToString(service->GetState()) << ");"
792 << check_command << ";"
793 << output << author_comment
796 msgbuf << "HOST NOTIFICATION: "
797 << user->GetName() << ";"
798 << host->GetName() << ";"
799 << notification_type_str << " "
800 << "(" << Host::StateToString(host->GetState()) << ");"
801 << check_command << ";"
802 << output << author_comment
806 AddLogHistory(checkable, msgbuf.str(), LogEntryTypeHostNotification);
809 void DbEvents::AddFlappingLogHistory(const Checkable::Ptr& checkable, FlappingState flapping_state)
811 String flapping_state_str;
812 String flapping_output;
814 switch (flapping_state) {
815 case FlappingStarted:
816 flapping_output = "Service appears to have started flapping (" + Convert::ToString(checkable->GetFlappingCurrent()) + "% change >= " + Convert::ToString(checkable->GetFlappingThreshold()) + "% threshold)";
817 flapping_state_str = "STARTED";
819 case FlappingStopped:
820 flapping_output = "Service appears to have stopped flapping (" + Convert::ToString(checkable->GetFlappingCurrent()) + "% change < " + Convert::ToString(checkable->GetFlappingThreshold()) + "% threshold)";
821 flapping_state_str = "STOPPED";
823 case FlappingDisabled:
824 flapping_output = "Flap detection has been disabled";
825 flapping_state_str = "DISABLED";
828 Log(LogCritical, "db_ido", "Unknown flapping state: " + Convert::ToString(flapping_state));
833 Service::Ptr service;
834 tie(host, service) = GetHostService(checkable);
836 std::ostringstream msgbuf;
839 msgbuf << "SERVICE FLAPPING ALERT: "
840 << host->GetName() << ";"
841 << service->GetShortName() << ";"
842 << flapping_state_str << "; "
846 msgbuf << "HOST FLAPPING ALERT: "
847 << host->GetName() << ";"
848 << flapping_state_str << "; "
853 AddLogHistory(checkable, msgbuf.str(), LogEntryTypeInfoMessage);
856 void DbEvents::AddLogHistory(const Checkable::Ptr& checkable, String buffer, LogEntryType type)
858 Log(LogDebug, "db_ido", "add log entry history for '" + checkable->GetName() + "'");
860 double now = Utility::GetTime();
861 std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
864 query1.Table = "logentries";
865 query1.Type = DbQueryInsert;
866 query1.Category = DbCatLog;
868 Dictionary::Ptr fields1 = make_shared<Dictionary>();
869 fields1->Set("logentry_time", DbValue::FromTimestamp(time_bag.first));
870 fields1->Set("entry_time", DbValue::FromTimestamp(time_bag.first));
871 fields1->Set("entry_time_usec", time_bag.second);
872 fields1->Set("object_id", checkable); // added in 1.10 see #4754
873 fields1->Set("logentry_type", type);
874 fields1->Set("logentry_data", buffer);
876 fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
878 String node = IcingaApplication::GetInstance()->GetNodeName();
880 Endpoint::Ptr endpoint = Endpoint::GetByName(node);
882 fields1->Set("endpoint_object_id", endpoint);
884 query1.Fields = fields1;
885 DbObject::OnQuery(query1);
888 /* flappinghistory */
889 void DbEvents::AddFlappingHistory(const Checkable::Ptr& checkable, FlappingState flapping_state)
891 Log(LogDebug, "db_ido", "add flapping history for '" + checkable->GetName() + "'");
893 double now = Utility::GetTime();
894 std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
897 query1.Table = "flappinghistory";
898 query1.Type = DbQueryInsert;
899 query1.Category = DbCatFlapping;
901 Dictionary::Ptr fields1 = make_shared<Dictionary>();
903 fields1->Set("event_time", DbValue::FromTimestamp(time_bag.first));
904 fields1->Set("event_time_usec", time_bag.second);
906 switch (flapping_state) {
907 case FlappingStarted:
908 fields1->Set("event_type", 1000);
910 case FlappingStopped:
911 fields1->Set("event_type", 1001);
912 fields1->Set("reason_type", 1);
914 case FlappingDisabled:
915 fields1->Set("event_type", 1001);
916 fields1->Set("reason_type", 2);
919 Log(LogDebug, "db_ido", "Unhandled flapping state: " + Convert::ToString(flapping_state));
924 Service::Ptr service;
925 tie(host, service) = GetHostService(checkable);
927 fields1->Set("flapping_type", service ? 1 : 0);
928 fields1->Set("object_id", checkable);
929 fields1->Set("percent_state_change", checkable->GetFlappingCurrent());
930 fields1->Set("low_threshold", checkable->GetFlappingThreshold());
931 fields1->Set("high_threshold", checkable->GetFlappingThreshold());
933 fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
935 String node = IcingaApplication::GetInstance()->GetNodeName();
937 Endpoint::Ptr endpoint = Endpoint::GetByName(node);
939 fields1->Set("endpoint_object_id", endpoint);
941 query1.Fields = fields1;
942 DbObject::OnQuery(query1);
946 void DbEvents::AddServiceCheckHistory(const Checkable::Ptr& checkable, const CheckResult::Ptr &cr)
951 Log(LogDebug, "db_ido", "add service check history for '" + checkable->GetName() + "'");
954 Service::Ptr service;
955 tie(host, service) = GetHostService(checkable);
957 std::ostringstream msgbuf;
960 query1.Table = service ? "servicechecks" : "hostchecks";
961 query1.Type = DbQueryInsert;
962 query1.Category = DbCatCheck;
964 Dictionary::Ptr fields1 = make_shared<Dictionary>();
965 double execution_time = Service::CalculateExecutionTime(cr);
967 fields1->Set("check_type", CompatUtility::GetCheckableCheckType(checkable));
968 fields1->Set("current_check_attempt", checkable->GetCheckAttempt());
969 fields1->Set("max_check_attempts", checkable->GetMaxCheckAttempts());
970 fields1->Set("state_type", checkable->GetStateType());
972 double now = Utility::GetTime();
973 std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
975 double end = now + execution_time;
976 std::pair<unsigned long, unsigned long> time_bag_end = CompatUtility::ConvertTimestamp(end);
978 fields1->Set("start_time", DbValue::FromTimestamp(time_bag.first));
979 fields1->Set("start_time_usec", time_bag.second);
980 fields1->Set("end_time", DbValue::FromTimestamp(time_bag_end.first));
981 fields1->Set("end_time_usec", time_bag_end.second);
982 fields1->Set("command_object_id", checkable->GetCheckCommand());
983 fields1->Set("command_args", Empty);
984 fields1->Set("command_line", cr->GetCommand());
985 fields1->Set("execution_time", Convert::ToString(execution_time));
986 fields1->Set("latency", Convert::ToString(Service::CalculateLatency(cr)));
987 fields1->Set("return_code", cr->GetExitStatus());
988 fields1->Set("output", CompatUtility::GetCheckResultOutput(cr));
989 fields1->Set("long_output", CompatUtility::GetCheckResultLongOutput(cr));
990 fields1->Set("perfdata", CompatUtility::GetCheckResultPerfdata(cr));
992 fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
995 fields1->Set("service_object_id", service);
996 fields1->Set("state", service->GetState());
998 fields1->Set("host_object_id", host);
999 fields1->Set("state", host->GetState());
1002 String node = IcingaApplication::GetInstance()->GetNodeName();
1004 Endpoint::Ptr endpoint = Endpoint::GetByName(node);
1006 fields1->Set("endpoint_object_id", endpoint);
1008 query1.Fields = fields1;
1009 DbObject::OnQuery(query1);
1013 void DbEvents::AddEventHandlerHistory(const Checkable::Ptr& checkable)
1015 Log(LogDebug, "db_ido", "add eventhandler history for '" + checkable->GetName() + "'");
1017 double now = Utility::GetTime();
1018 std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
1021 query1.Table = "eventhandlers";
1022 query1.Type = DbQueryInsert;
1023 query1.Category = DbCatEventHandler;
1025 Dictionary::Ptr fields1 = make_shared<Dictionary>();
1028 Service::Ptr service;
1029 tie(host, service) = GetHostService(checkable);
1031 fields1->Set("eventhandler_type", service ? 1 : 0);
1032 fields1->Set("object_id", checkable);
1033 fields1->Set("state", service ? service->GetState() : host->GetState());
1034 fields1->Set("state_type", checkable->GetStateType());
1036 fields1->Set("start_time", DbValue::FromTimestamp(time_bag.first));
1037 fields1->Set("start_time_usec", time_bag.second);
1038 fields1->Set("end_time", DbValue::FromTimestamp(time_bag.first));
1039 fields1->Set("end_time_usec", time_bag.second);
1040 fields1->Set("command_object_id", checkable->GetEventCommand());
1042 fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
1044 String node = IcingaApplication::GetInstance()->GetNodeName();
1046 Endpoint::Ptr endpoint = Endpoint::GetByName(node);
1048 fields1->Set("endpoint_object_id", endpoint);
1050 query1.Fields = fields1;
1051 DbObject::OnQuery(query1);
1054 /* externalcommands */
1055 void DbEvents::AddExternalCommandHistory(double time, const String& command, const std::vector<String>& arguments)
1057 Log(LogDebug, "db_ido", "add external command history");
1060 query1.Table = "externalcommands";
1061 query1.Type = DbQueryInsert;
1062 query1.Category = DbCatExternalCommand;
1064 Dictionary::Ptr fields1 = make_shared<Dictionary>();
1066 fields1->Set("entry_time", DbValue::FromTimestamp(static_cast<long>(time)));
1067 fields1->Set("command_type", CompatUtility::MapExternalCommandType(command));
1068 fields1->Set("command_name", command);
1069 fields1->Set("command_args", boost::algorithm::join(arguments, ";"));
1071 fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
1073 String node = IcingaApplication::GetInstance()->GetNodeName();
1075 Endpoint::Ptr endpoint = Endpoint::GetByName(node);
1077 fields1->Set("endpoint_object_id", endpoint);
1079 query1.Fields = fields1;
1080 DbObject::OnQuery(query1);