@@ -134,7 +134,7 @@ func main() {
134134 log .Printf ("DEBUG: Creating new server: %v" , servers [k ].URL )
135135 }
136136 if err != nil {
137- log .Printf ("INFO: Server %s is dead." , servers [k ].URL )
137+ log .Printf ("INFO : Server %s is dead." , servers [k ].URL )
138138 servers [k ].State = STATE_FAILED
139139 continue
140140 }
@@ -255,8 +255,14 @@ func main() {
255255 switch event .Type {
256256 case termbox .EventKey :
257257 if event .Key == termbox .KeyCtrlS {
258- command = "switchover"
259- exit = true
258+ nmUrl , nsKey := master .switchover ()
259+ if nmUrl != "" && nsKey >= 0 {
260+ if * verbose {
261+ logprintf ("DEBUG: Reinstancing new master: %s and new slave: %s [%d]" , nmUrl , slaves [nsKey ].URL , nsKey )
262+ }
263+ master , err = newServerMonitor (nmUrl )
264+ slaves [nsKey ], err = newServerMonitor (slaves [nsKey ].URL )
265+ }
260266 }
261267 if event .Key == termbox .KeyCtrlF {
262268 command = "failover"
@@ -276,22 +282,9 @@ func main() {
276282 exit = true
277283 }
278284 }
279- termbox .Close ()
280285 switch command {
281- case "switchover" :
282- nmUrl , nsKey := master .switchover ()
283- if nmUrl != "" && nsKey >= 0 {
284- if * verbose {
285- log .Printf ("DEBUG: Reinstancing new master: %s and new slave: %s [%d]" , nmUrl , slaves [nsKey ].URL , nsKey )
286- }
287- master , err = newServerMonitor (nmUrl )
288- slaves [nsKey ], err = newServerMonitor (slaves [nsKey ].URL )
289- }
290- log .Println ("###### Restarting monitor console in 5 seconds. Press Ctrl-C to exit" )
291- time .Sleep (5 * time .Second )
292- exit = false
293- goto MainLoop
294286 case "failover" :
287+ termbox .Close ()
295288 nmUrl , nmKey := master .failover ()
296289 if nmUrl != "" {
297290 if * verbose {
@@ -306,6 +299,7 @@ func main() {
306299 exit = false
307300 goto MainLoop
308301 }
302+ termbox .Close ()
309303 }
310304}
311305
@@ -379,138 +373,138 @@ func (sm *ServerMonitor) healthCheck() string {
379373
380374/* Triggers a master switchover. Returns the new master's URL */
381375func (master * ServerMonitor ) switchover () (string , int ) {
382- log . Println ("INFO : Starting switchover" )
376+ logprint ("INFO : Starting switchover" )
383377 // Phase 1: Cleanup and election
384- log . Printf ("INFO : Flushing tables on %s (master)" , master .URL )
378+ logprintf ("INFO : Flushing tables on %s (master)" , master .URL )
385379 err := dbhelper .FlushTablesNoLog (master .Conn )
386380 if err != nil {
387- log . Printf ("WARN : Could not flush tables on master" , err )
381+ logprintf ("WARN : Could not flush tables on master" , err )
388382 }
389- log . Println ("INFO : Checking long running updates on master" )
383+ logprint ("INFO : Checking long running updates on master" )
390384 if dbhelper .CheckLongRunningWrites (master .Conn , 10 ) > 0 {
391- log . Println ("ERROR: Long updates running on master. Cannot switchover" )
385+ logprint ("ERROR: Long updates running on master. Cannot switchover" )
392386 return "" , - 1
393387 }
394- log . Println ("INFO : Electing a new master" )
388+ logprint ("INFO : Electing a new master" )
395389 var nmUrl string
396390 key := master .electCandidate (slaves )
397391 if key == - 1 {
398392 return "" , - 1
399393 }
400394 nmUrl = slaves [key ].URL
401- log . Printf ("INFO : Slave %s has been elected as a new master" , nmUrl )
395+ logprintf ("INFO : Slave %s has been elected as a new master" , nmUrl )
402396 newMaster , err := newServerMonitor (nmUrl )
403397 if * preScript != "" {
404- log . Printf ("INFO : Calling pre-failover script" )
398+ logprintf ("INFO : Calling pre-failover script" )
405399 out , err := exec .Command (* preScript , master .Host , newMaster .Host ).CombinedOutput ()
406400 if err != nil {
407- log . Println ("ERROR:" , err )
401+ logprint ("ERROR:" , err )
408402 }
409- log . Println ("INFO : Pre-failover script complete:" , string (out ))
403+ logprint ("INFO : Pre-failover script complete:" , string (out ))
410404 }
411405 // Phase 2: Reject updates and sync slaves
412406 master .freeze ()
413- log . Printf ("INFO : Rejecting updates on %s (old master)" , master .URL )
407+ logprintf ("INFO : Rejecting updates on %s (old master)" , master .URL )
414408 err = dbhelper .FlushTablesWithReadLock (master .Conn )
415409 if err != nil {
416- log . Printf ("WARN : Could not lock tables on %s (old master) %s" , master .URL , err )
410+ logprintf ("WARN : Could not lock tables on %s (old master) %s" , master .URL , err )
417411 }
418- log . Println ("INFO : Switching master" )
419- log . Println ("INFO : Waiting for candidate master to synchronize" )
412+ logprint ("INFO : Switching master" )
413+ logprint ("INFO : Waiting for candidate master to synchronize" )
420414 masterGtid := dbhelper .GetVariableByName (master .Conn , "GTID_BINLOG_POS" )
421415 if * verbose {
422- log . Printf ("DEBUG: Syncing on master GTID Current Pos [%s]" , masterGtid )
416+ logprintf ("DEBUG: Syncing on master GTID Current Pos [%s]" , masterGtid )
423417 master .log ()
424418 }
425419 dbhelper .MasterPosWait (newMaster .Conn , masterGtid )
426420 if * verbose {
427- log . Println ("DEBUG: MASTER_POS_WAIT executed." )
421+ logprint ("DEBUG: MASTER_POS_WAIT executed." )
428422 newMaster .log ()
429423 }
430424 // Phase 3: Prepare new master
431- log . Println ("INFO: Stopping slave thread on new master" )
425+ logprint ("INFO : Stopping slave thread on new master" )
432426 err = dbhelper .StopSlave (newMaster .Conn )
433427 if err != nil {
434- log . Println ("WARN : Stopping slave failed on new master" )
428+ logprint ("WARN : Stopping slave failed on new master" )
435429 }
436430 // Call post-failover script before unlocking the old master.
437431 if * postScript != "" {
438- log . Printf ("INFO : Calling post-failover script" )
432+ logprintf ("INFO : Calling post-failover script" )
439433 out , err := exec .Command (* postScript , master .Host , newMaster .Host ).CombinedOutput ()
440434 if err != nil {
441- log . Println ("ERROR:" , err )
435+ logprint ("ERROR:" , err )
442436 }
443- log . Println ("INFO : Post-failover script complete" , string (out ))
437+ logprint ("INFO : Post-failover script complete" , string (out ))
444438 }
445- log . Println ("INFO : Resetting slave on new master and set read/write mode on" )
439+ logprint ("INFO : Resetting slave on new master and set read/write mode on" )
446440 err = dbhelper .ResetSlave (newMaster .Conn , true )
447441 if err != nil {
448- log . Println ("WARN : Reset slave failed on new master" )
442+ logprint ("WARN : Reset slave failed on new master" )
449443 }
450444 // Phase 4: Demote old master to slave
451445 err = dbhelper .SetReadOnly (newMaster .Conn , false )
452446 if err != nil {
453- log . Println ("ERROR: Could not set new master as read-write" )
447+ logprint ("ERROR: Could not set new master as read-write" )
454448 }
455449 cm := "CHANGE MASTER TO master_host='" + newMaster .IP + "', master_port=" + newMaster .Port + ", master_user='" + rplUser + "', master_password='" + rplPass + "'"
456- log . Println ("INFO : Switching old master as a slave" )
450+ logprint ("INFO : Switching old master as a slave" )
457451 err = dbhelper .UnlockTables (master .Conn )
458452 if err != nil {
459- log . Println ("WARN : Could not unlock tables on old master" , err )
453+ logprint ("WARN : Could not unlock tables on old master" , err )
460454 }
461455 dbhelper .StopSlave (master .Conn ) // This is helpful because in some cases the old master can have an old configuration running
462456 _ , err = master .Conn .Exec (cm + ", master_use_gtid=current_pos" )
463457 if err != nil {
464- log . Println ("WARN : Change master failed on old master" , err )
458+ logprint ("WARN : Change master failed on old master" , err )
465459 }
466460 err = dbhelper .StartSlave (master .Conn )
467461 if err != nil {
468- log . Println ("WARN : Start slave failed on old master" , err )
462+ logprint ("WARN : Start slave failed on old master" , err )
469463 }
470464 if * readonly {
471465 err = dbhelper .SetReadOnly (master .Conn , true )
472466 if err != nil {
473- log . Printf ("ERROR: Could not set old master as read-only, %s" , err )
467+ logprintf ("ERROR: Could not set old master as read-only, %s" , err )
474468 }
475469 }
476470 // Phase 5: Switch slaves to new master
477- log . Println ("INFO : Switching other slaves to the new master" )
471+ logprint ("INFO : Switching other slaves to the new master" )
478472 var oldMasterKey int
479473 for k , sl := range slaves {
480474 if sl .URL == newMaster .URL {
481475 slaves [k ].URL = master .URL
482476 oldMasterKey = k
483477 if * verbose {
484- log . Printf ("DEBUG: New master %s found in slave slice at key %d, reinstancing URL to %s" , sl .URL , k , master .URL )
478+ logprintf ("DEBUG: New master %s found in slave slice at key %d, reinstancing URL to %s" , sl .URL , k , master .URL )
485479 }
486480 continue
487481 }
488- log . Printf ("INFO : Waiting for slave %s to sync" , sl .URL )
482+ logprintf ("INFO : Waiting for slave %s to sync" , sl .URL )
489483 dbhelper .MasterPosWait (sl .Conn , masterGtid )
490484 if * verbose {
491485 sl .log ()
492486 }
493- log . Printf ("INFO : Change master on slave %s" , sl .URL )
487+ logprintf ("INFO : Change master on slave %s" , sl .URL )
494488 err := dbhelper .StopSlave (sl .Conn )
495489 if err != nil {
496- log . Printf ("WARN : Could not stop slave on server %s, %s" , sl .URL , err )
490+ logprintf ("WARN : Could not stop slave on server %s, %s" , sl .URL , err )
497491 }
498492 _ , err = sl .Conn .Exec (cm )
499493 if err != nil {
500- log . Printf ("ERROR: Change master failed on slave %s, %s" , sl .URL , err )
494+ logprintf ("ERROR: Change master failed on slave %s, %s" , sl .URL , err )
501495 }
502496 err = dbhelper .StartSlave (sl .Conn )
503497 if err != nil {
504- log . Printf ("ERROR: could not start slave on server %s, %s" , sl .URL , err )
498+ logprintf ("ERROR: could not start slave on server %s, %s" , sl .URL , err )
505499 }
506500 if * readonly {
507501 err = dbhelper .SetReadOnly (sl .Conn , true )
508502 if err != nil {
509- log . Printf ("ERROR: Could not set slave %s as read-only, %s" , sl .URL , err )
503+ logprintf ("ERROR: Could not set slave %s as read-only, %s" , sl .URL , err )
510504 }
511505 }
512506 }
513- log . Println ("INFO : Switchover complete" )
507+ logprint ("INFO : Switchover complete" )
514508 return newMaster .URL , oldMasterKey
515509}
516510
@@ -587,18 +581,18 @@ func (master *ServerMonitor) failover() (string, int) {
587581func (server * ServerMonitor ) freeze () bool {
588582 err := dbhelper .SetReadOnly (server .Conn , true )
589583 if err != nil {
590- log . Printf ("WARN : Could not set %s as read-only: %s" , server .URL , err )
584+ logprintf ("WARN : Could not set %s as read-only: %s" , server .URL , err )
591585 return false
592586 }
593587 for i := * waitKill ; i > 0 ; i -= 500 {
594588 threads := dbhelper .CheckLongRunningWrites (server .Conn , 0 )
595589 if threads == 0 {
596590 break
597591 }
598- log . Printf ("INFO : Waiting for %d write threads to complete on %s" , threads , server .URL )
592+ logprintf ("INFO : Waiting for %d write threads to complete on %s" , threads , server .URL )
599593 time .Sleep (500 * time .Millisecond )
600594 }
601- log . Printf ("INFO: Terminating all threads on %s" , server .URL )
595+ logprintf ("INFO : Terminating all threads on %s" , server .URL )
602596 dbhelper .KillThreads (server .Conn )
603597 return true
604598}
@@ -644,45 +638,45 @@ func validateHostPort(h string, p string) bool {
644638func (master * ServerMonitor ) electCandidate (l []* ServerMonitor ) int {
645639 ll := len (l )
646640 if * verbose {
647- log . Printf ("DEBUG: Processing %d candidates" , ll )
641+ logprintf ("DEBUG: Processing %d candidates" , ll )
648642 }
649643 seqList := make ([]uint64 , ll )
650644 i := 0
651645 hiseq := 0
652646 for _ , sl := range l {
653647 if * failover == "" {
654648 if * verbose {
655- log . Printf ("DEBUG: Checking eligibility of slave server %s" , sl .URL )
649+ logprintf ("DEBUG: Checking eligibility of slave server %s" , sl .URL )
656650 }
657651 if dbhelper .CheckSlavePrerequisites (sl .Conn , sl .Host ) == false {
658652 continue
659653 }
660654 if dbhelper .CheckBinlogFilters (master .Conn , sl .Conn ) == false {
661- log . Printf ("WARN : Binlog filters differ on master and slave %s. Skipping" , sl .URL )
655+ logprintf ("WARN : Binlog filters differ on master and slave %s. Skipping" , sl .URL )
662656 continue
663657 }
664658 if dbhelper .CheckReplicationFilters (master .Conn , sl .Conn ) == false {
665- log . Printf ("WARN : Replication filters differ on master and slave %s. Skipping" , sl .URL )
659+ logprintf ("WARN : Replication filters differ on master and slave %s. Skipping" , sl .URL )
666660 continue
667661 }
668662 ss , _ := dbhelper .GetSlaveStatus (sl .Conn )
669663 if ss .Seconds_Behind_Master .Valid == false {
670- log . Printf ("WARN : Slave %s is stopped. Skipping" , sl .URL )
664+ logprintf ("WARN : Slave %s is stopped. Skipping" , sl .URL )
671665 continue
672666 }
673667 if ss .Seconds_Behind_Master .Int64 > * maxDelay {
674- log . Printf ("WARN : Slave %s has more than %d seconds of replication delay (%d). Skipping" , sl .URL , * maxDelay , ss .Seconds_Behind_Master .Int64 )
668+ logprintf ("WARN : Slave %s has more than %d seconds of replication delay (%d). Skipping" , sl .URL , * maxDelay , ss .Seconds_Behind_Master .Int64 )
675669 continue
676670 }
677671 if * gtidCheck && dbhelper .CheckSlaveSync (sl .Conn , master .Conn ) == false {
678- log . Printf ("WARN : Slave %s not in sync. Skipping" , sl .URL )
672+ logprintf ("WARN : Slave %s not in sync. Skipping" , sl .URL )
679673 continue
680674 }
681675 }
682676 /* Rig the election if the examined slave is preferred candidate master */
683677 if sl .URL == * prefMaster {
684678 if * verbose {
685- log . Printf ("DEBUG: Election rig: %s elected as preferred master" , sl .URL )
679+ logprintf ("DEBUG: Election rig: %s elected as preferred master" , sl .URL )
686680 }
687681 return i
688682 }
@@ -707,7 +701,7 @@ func (master *ServerMonitor) electCandidate(l []*ServerMonitor) int {
707701
708702func (server * ServerMonitor ) log () {
709703 server .refresh ()
710- log . Printf ("DEBUG: Server:%s Current GTID:%s Slave GTID:%s Binlog Pos:%s\n " , server .URL , server .CurrentGtid , server .SlaveGtid , server .BinlogPos )
704+ logprintf ("DEBUG: Server:%s Current GTID:%s Slave GTID:%s Binlog Pos:%s\n " , server .URL , server .CurrentGtid , server .SlaveGtid , server .BinlogPos )
711705 return
712706}
713707
@@ -777,7 +771,7 @@ func display() {
777771 printTb (0 , vy , termbox .ColorWhite , termbox .ColorBlack , " Ctrl-Q to quit, Ctrl-F to failover" )
778772 }
779773 vy = vy + 3
780- tlog .Print (& vy )
774+ tlog .Print ()
781775 termbox .Flush ()
782776}
783777
@@ -801,11 +795,10 @@ func (tl *TermLog) Add(s string) {
801795 * tl = shift (* tl , s )
802796}
803797
804- func (tl TermLog ) Print (vy * int ) {
805- //log.Println(tl)
798+ func (tl TermLog ) Print () {
806799 for _ , line := range tl {
807- printTb (0 , * vy , termbox .ColorWhite , termbox .ColorBlack , line )
808- * vy ++
800+ printTb (0 , vy , termbox .ColorWhite , termbox .ColorBlack , line )
801+ vy ++
809802 }
810803}
811804
@@ -821,6 +814,24 @@ func printfTb(x, y int, fg, bg termbox.Attribute, format string, args ...interfa
821814 printTb (x , y , fg , bg , s )
822815}
823816
817+ func logprint (msg ... interface {}) {
818+ if * interactive == true || * failover == "monitor" {
819+ tlog .Add (fmt .Sprintln (msg ... ))
820+ display ()
821+ } else {
822+ log .Println (msg ... )
823+ }
824+ }
825+
826+ func logprintf (format string , args ... interface {}) {
827+ if * interactive == true || * failover == "monitor" {
828+ tlog .Add (fmt .Sprintf (format , args ... ))
829+ display ()
830+ } else {
831+ log .Printf (format , args ... )
832+ }
833+ }
834+
824835func new_tb_chan () chan termbox.Event {
825836 termboxChan := make (chan termbox.Event )
826837 go func () {
@@ -834,7 +845,7 @@ func new_tb_chan() chan termbox.Event {
834845func shift (s []string , e string ) []string {
835846 ns := make ([]string , 1 )
836847 ns [0 ] = e
837- ns = append (ns , s [0 :9 ]... )
848+ ns = append (ns , s [0 :20 ]... )
838849 return ns
839850}
840851
0 commit comments