Subversion Repositories DevTools

Rev

Rev 7387 | Rev 7394 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
7387 dpurdie 1
#! /usr/bin/perl
2
########################################################################
3
# COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED.
4
#
5
# Module name   : blatTarZip.pl
6
# Module type   :
7
# Compiler(s)   : Perl
8
# Environment(s):
9
#
10
# Description   :   This is a blat related task that will monitor a
11
#                   directory for requests to tarZip a package
12
#
13
# Usage         :   ARGV[0] - Path to config file for this instance
14
#
15
#......................................................................#
16
 
17
require 5.008_002;
18
use strict;
19
use warnings;
20
use Getopt::Long;
21
use File::Basename;
22
use Data::Dumper;
23
use File::Spec::Functions;
24
use POSIX ":sys_wait_h";
25
use File::Temp qw/tempfile/;
26
use Digest::MD5;
27
 
28
use FindBin;                                    # Determine the current directory
29
use lib "$FindBin::Bin/lib";                    # Allow local libraries
30
 
31
use Utils;
32
use StdLogger;                                  # Log to sdtout
33
use Logger;                                     # Log to file
34
 
35
#
36
#   Database interface
37
#   Pinched from jats and modified so that this software is not dependent on JATS
38
#
39
use IO::Handle;
40
use JatsRmApi;
41
use DBI;
42
 
43
#
44
#   Globals
45
#
46
my $logger = StdLogger->new();                  # Stdout logger. Only during config
47
$logger->err("No config file specified") unless (defined $ARGV[0]);
48
$logger->err("Config File does not exist: $ARGV[0]") unless (-f $ARGV[0]);
49
my $name = basename( $ARGV[0]);
50
   $name =~ s~.conf$~~;
51
my $now = 0;
52
my $startTime = 0;
53
my $tagDirTime = 0;
54
my $lastDirScan = 0;
55
my $lastCleanScan =  0;
56
my $mtimeConfig = 0;
57
my $conf;
58
my $yday = -1;
59
my $tagRoot;
60
 
61
#
62
#   Contain statisics maintained while operating
63
#       Can be dumped with a kill -USR2
64
#       List here for documentation
65
#  
66
 
67
my %statistics = (
68
    SeqNum => 0,                        # Bumped when $statistics are dumped
69
    timeStamp => 0,                     # DateTime when statistics are dumped
70
    upTime => 0,                        # Seconds since program start
71
    Cycle => 0,                         # Major process loop counter
72
    phase => 'Init',                    # Current phase of operation
73
    state => 'OK',                      # Nagios state
74
                                        # 
75
                                        # The following are reset each day
76
    dayStart => 0,                      # DateTime when daily data was reset
77
    txCount => 0,                       # Packages Transferred
78
    delCount => 0,                      # Packages marked for deletion
79
    staleTags => 0,                     # Stale Tags
80
    linkErrors => 0,                    # Transfer (zip) errors
81
                                        # 
82
                                        # Per Cycle Data - Calculated each processing Cycle
83
    total    => 0,                      # Packages to be synced
84
    delete   => 0,                      # Packages to delete
85
    excluded => 0,                      # Packages excluded    
86
    filtered => 0,                      # Packages filtered out
87
    missing  => 0,                      # Packages missing
88
    transfer => 0,                      # Packages to transfer
89
    writable => 0,                      # Packages still writable - thus not transferred
90
    tagCount => 0,                      # Packages tagged to be transferred
91
                                        #
92
);
93
 
94
#
95
#   Describe configuration parameters
96
#
97
my %cdata = (
98
    'piddir'          => {'mandatory' => 1      , 'fmt' => 'dir'},
99
    'sleep'           => {'default'   => 5      , 'fmt' => 'period'},
100
    'dpkg_archive'    => {'mandatory' => 1      , 'fmt' => 'dir'},
101
    'logfile'         => {'mandatory' => 1      , 'fmt' => 'vfile'},
102
    'logfile.size'    => {'default'   => '1M'   , 'fmt' => 'size'},
103
    'logfile.count'   => {'default'   => 9      , 'fmt' => 'int'},
104
    'verbose'         => {'default'   => 0      , 'fmt' => 'int'},
105
    'active'          => {'default'   => 1      , 'fmt' => 'bool'},
106
    'debug'           => {'default'   => 0      , 'fmt' => 'bool'},                 # Log to screen
107
    'tagdir'          => {'mandatory' => 1      , 'fmt' => 'dir'},
108
    'forcedirscan'    => {'default'   => 100    , 'fmt' => 'period'},
109
    'tagMaxPackages'  => {'default'   => 10     , 'fmt' => 'int'},
110
    'tagage'          => {'default'   => '10d'  , 'fmt' => 'period'},
111
    'cleanPeriod'     => {'default'   => '30m'  , 'fmt' => 'period'},
7389 dpurdie 112
    'maxFileAge'      => {'default'   => '24h'  , 'fmt' => 'period'},
113
    'txdetail'        => {'default'   => 0      , 'fmt' => 'bool'},
7387 dpurdie 114
 
115
 
116
);
117
 
118
 
119
#
120
#   Read in the configuration
121
#       Set up a logger
122
#       Write a pidfile - thats not used
123
$now = $startTime = time();
124
readConfig();
125
Utils::writepid($conf);
126
$logger->logmsg("Starting...");
127
readStatistics();
128
sighandlers($conf);
129
 
130
#
131
#   Main processing loop
132
#   Will exit when terminated by parent
133
#
134
while (1)
135
{
136
    $logger->verbose3("Processing");
137
    $statistics{Cycle}++;
138
    $now = time();
139
 
140
    $statistics{phase} = 'ReadConfig';
141
    readConfig();
142
    if ( $conf->{'active'} )
143
    {
144
        $statistics{phase} = 'Monitor Tags';
145
        processRequests();
146
        cleanZipStore();
147
    }
148
 
149
    $statistics{phase} = 'Sleep';
150
    sleep( $conf->{'sleep'} );
151
    reapChildren();
152
 
153
    #   If my PID file ceases to be, then exit the daemon
154
    #   Used to force daemon to restart
155
    #
156
    unless ( -f $conf->{'pidfile'} )
157
    {
158
        $logger->logmsg("Terminate. Pid file removed");
159
        last;
160
    }
161
}
162
$statistics{phase} = 'Terminated';
163
$logger->logmsg("Child End");
164
exit 0;
165
 
166
#-------------------------------------------------------------------------------
167
# Function        : reapChildren 
168
#
169
# Description     : Reap any and all dead children
170
#                   Call in major loops to prevent zombies accumulating 
171
#
172
# Inputs          : None
173
#
174
# Returns         : 
175
#
176
sub reapChildren
177
{
178
    my $currentPhase = $statistics{phase};
179
    $statistics{phase} = 'Reaping';
180
 
181
    my $kid;
182
    do {
183
        $kid = waitpid(-1, WNOHANG);
184
    } while ( $kid > 0 );
185
 
186
    $statistics{phase} = $currentPhase;
187
}
188
 
189
 
190
#-------------------------------------------------------------------------------
191
# Function        : readConfig
192
#
193
# Description     : Re read the config file if it modification time has changed
194
#
195
# Inputs          : Nothing
196
#
197
# Returns         : 0       - Config not read
198
#                   1       - Config read
199
#                             Config file has changed
200
#
201
sub readConfig
202
{
203
    my ($mtime) = Utils::mtime($ARGV[0]);
204
    my $rv = 0;
205
 
206
    if ( $mtimeConfig != $mtime )
207
    {
208
        $logger->logmsg("Reading config file: $ARGV[0]");
209
        $mtimeConfig = $mtime;
210
        my $errors;
211
        ($conf, $errors) = Utils::readconf ( $ARGV[0], \%cdata );
212
        if ( scalar @{$errors} > 0 )
213
        {
214
            warn "$_\n" foreach (@{$errors});
215
            die ("Config contained errors\n");
216
        }
217
 
218
        #
219
        #   Reset some information
220
        #   Create a new logger
221
        #
222
        $logger = Logger->new($conf) unless $conf->{debug};
223
        $conf->{logger} = $logger;
224
        $conf->{'pidfile'} = $conf->{'piddir'} . '/' . $name . '.pid';
225
        $logger->setVerbose($conf->{verbose});
226
        $logger->verbose("Log Levl: $conf->{verbose}");
227
 
228
        #
229
        #   Setup statistics filename
230
        $conf->{'statsfile'} = $conf->{'piddir'} . '/' . $name . '.stats';
231
        $conf->{'statsfiletmp'} = $conf->{'piddir'} . '/' . $name . '.stats.tmp';
232
 
233
        #
234
        #   Calculate the base of the tags directory
235
        #   ASSUME all tagdirs are in the same tree as my tags dir
236
        #
237
        $conf->{'tagdir'} =~ m~^(.*)/~;
238
        $tagRoot = $1;
239
    }
240
 
241
    #
242
    #   When config is read force some actions
243
 
244
#Utils::DebugDumpData ("Config", $conf);
245
 
246
    $logger->warn("Tar Zip is inactive") unless ( $conf->{'active'} );
247
    return $rv;
248
}
249
 
250
 
251
#-------------------------------------------------------------------------------
252
# Function        : processRequests
253
#
254
# Description     : Process tags and generate tarZip files as required
255
#                       Determine if new tags are present
256
#                       Process each tag
257
#
258
# Inputs          : None
259
#
260
# Returns         : Nothing
261
#
262
sub processRequests
263
{
264
    #
265
    #   Determine if new tags are present by examining the time
266
    #   that the directory was last modified.
267
    #
268
    #   Allow for a forced scan to catch packages that did not transfer
269
    #   on the first attempt
270
    #
271
    my $tagCount = 0;
272
    my ($mtime) = Utils::mtime($conf->{'tagdir'} );
273
    if ( ($mtime > $tagDirTime) || ($now > ($lastDirScan + $conf->{'forcedirscan'})) )
274
    {
275
        $logger->verbose2("processTags: ,$conf->{'tagdir'}");
276
        $tagDirTime = $mtime;
277
        $lastDirScan = $now;
278
        my $txcount = $conf->{'tagMaxPackages'};
279
 
280
 
281
        my $dh;
282
        unless (opendir($dh, $conf->{'tagdir'}))
283
        {
284
            $logger->warn ("can't opendir $conf->{'tagdir'}: $!");
285
            return;
286
        }
287
 
288
        #
289
        #   Process each entry
290
        #   Ignore those that start with a .
291
        #
292
        my %tagPkgList;
293
        while (my $tag = readdir($dh) )
294
        {
295
            next if ( $tag =~ m~^\.~ );
296
            my $file = "$conf->{'tagdir'}/$tag";
297
            $logger->verbose3("processTags: $file");
298
 
299
            if ( $tag =~ m~(.+)::(.+)~  )
300
            {
301
                my $package = $1;
302
                my $version = $2;
303
                $tagCount++;
304
                $tagPkgList{$package}{$version} = $file;
305
            }
306
        }
307
        $statistics{tagCount} = $tagCount;
308
        closedir $dh;
309
 
310
        #
311
        #   Process the packages located in the tags area
312
        #
313
        send_tags:
314
        while ( (my ($package, $pvers)) = each %{tagPkgList} )
315
        {
316
            while ( (my ($version, $file) ) = each %{$pvers} )
317
            {
318
                if ( --$txcount <= 0 )
319
                {
320
                    $logger->warn("Max tag transfer count exceeded: $tagCount transfer remaining");
321
                    $tagDirTime = 0;
322
                    last send_tags;
323
                }
324
 
325
                if ( readConfig() )
326
                {
327
                    $logger->warn("Config file changed");
328
                    $txcount = 0;
329
                    $tagDirTime = 0;
330
                    last send_tags;
331
                }
332
 
333
                #
334
                #
335
                if ( tarZipPackage( $package, $version )) {
336
                    unlink $file;
337
                    triggerTransfers($package, $version);
338
                }
339
                else
340
                {
341
                    if ($conf->{'tagage'} > 0) {
342
                        my ($mtime) = Utils::mtime( $file );
343
                        if ( $now - $mtime > $conf->{'tagage'} )
344
                        {
345
                            $logger->warn ("Delete unsatisfied tag: $package::$version after $conf->{'tagage'}" );
346
                            unlink $file;
347
                            $statistics{staleTags}++;
348
                        }
349
                    }
350
                }
351
 
352
                $tagCount--;
353
                reapChildren();
354
            }
355
        }
356
    }
357
}
358
 
359
#-------------------------------------------------------------------------------
360
# Function        : cleanZipStore  
361
#
362
# Description     : Cleanup the store of zipped packages
363
#                   If a tarZip is no longer needed for a transfer, then we can consider
364
#                   removing it from the store
365
#                   
366
#                   May want to keep it for some time, but ...
367
#                   
368
#                   May need to remove them if they are too old.
369
#                   When a connection is wedged, then we may end up with a lot of packages
370
#                   May be that the ssh tx process will age out old tags, but I don't think so 
371
#                   
372
#                   Should be run periodically
373
#
374
# Inputs          : 
375
#
376
# Returns         : 
377
#
378
sub cleanZipStore
379
{
380
    if ( $conf->{cleanPeriod} == 0 )
381
    {
382
        $logger->verbose2("cleanZipStore disabled");
383
        return;
384
    }
385
 
386
    #
387
    #   Time to perform the scan
388
    #   Will do at startup and every time period there after
389
    #
390
    return unless ( $now > ($lastCleanScan + $conf->{cleanPeriod} ));
391
    $logger->verbose("cleanZipStore");
392
    $lastCleanScan = $now;
393
 
394
 
395
    my %tagPkgList;
396
    #
397
    #   Locate all the tags and create a hash of known tags
398
    #   These are packages that we have queued to be transferred
399
    #
400
    my @tagList = glob ("$tagRoot/*/*::*");
401
 
402
    foreach my $entry ( @tagList )
403
    {
404
        $entry =~ m~.*/(.*)::(.*)$~;
405
        $tagPkgList{$1 .'__'.$2 . '.tgz'} = 1;
406
    }
407
 
408
    #
409
    #   Iterate over all the stored tarZips and remove them if they are no longer needed
410
    #
411
    my @tarZipFiles = glob (catfile( $conf->{'dpkg_archive'}, '.dpkg_archive', 'tarStore', '*.tgz' ));
412
    foreach my $entry  (@tarZipFiles) {
413
        $entry =~ m~.*/(.*)$~;
414
        my $fname = $1;
415
 
416
        if (!exists $tagPkgList{$fname}) {
7389 dpurdie 417
 
418
            my ($mtime) = Utils::mtime($entry);
419
            my $age = time() - $mtime;
420
            $logger->verbose3( "File Age: $age, $conf->{maxFileAge}");
421
            if ( $age > $conf->{maxFileAge} ) {
422
                $logger->logmsg("cleanZipStore. Remove: $fname");
423
                unlink $entry;
424
                $logger->warn("cleanZipStore. Cannot Remove: $fname") if (-f $entry);
425
            }
7387 dpurdie 426
        } else {
427
            $logger->verbose("cleanZipStore. Retain: $fname");
428
 
429
        }
430
    }
431
 
432
}
433
 
434
 
435
#-------------------------------------------------------------------------------
436
# Function        : tarZipPackage 
437
#
438
# Description     : Perform the tar Zip operation 
439
#
440
# Inputs          : $pname
441
#                   $version 
442
#
443
# Returns         : 1 - TarZip complete
444
#                   0 - TarZip not complete 
445
#
446
sub tarZipPackage
447
{
448
    my ($pname, $version) = @_;
449
    $logger->logmsg("TarZip $pname $version");
450
 
451
    my $pkgName = $pname .'_'.$version;
452
    my $srcDir = catdir( $conf->{'dpkg_archive'}, $pname, $version);
453
    my $tgtdir = catfile( $conf->{'dpkg_archive'}, '.dpkg_archive', 'tarStore' );
454
    my $zfile = $pname . '__' . $version . '.tgz';
455
    my $tfile = catfile($tgtdir, $zfile);
456
    my $tfileTmp = $tfile . '.TEMP';
7389 dpurdie 457
    my $startTime = time;
7387 dpurdie 458
 
459
    #
460
    #   Does the source exist
461
    if (! -d $srcDir) {
462
        $logger->warn("Package not found: $pname, $version");
463
        return 0;
464
    }
465
 
466
    #
467
    #   If the target zip is already present, then assume the job has been done
468
    #   
469
    if ( -f $tfile ) {
470
        $logger->verbose("tarZipPackage: Already done: $pname, $version");
471
        $logger->verbose2("tarZipPackage: Already done: $pname, $version - $tfile");
472
        return 1;
473
    }
474
 
475
    #
476
    #   Tar zip the file
477
    #       TarZip into a temp file, then rename it
478
    #
479
    my $tar_cmd = "tar -czf $tfileTmp -C  $conf->{'dpkg_archive'} $pname/$version";
480
    $logger->verbose2("tarZipPackage:tar_cmd:$tar_cmd");
481
 
482
    my $ph;
483
    my $cmdRv;
484
    open ($ph, "$tar_cmd |");
485
    while ( <$ph> )
486
    {
487
        chomp;
488
        $logger->verbose2("tarZipPackage:Data: $_");
489
    }
490
    close ($ph);
491
    $cmdRv = $?;
492
    $logger->verbose("tarZipPackage:End: $cmdRv");
493
 
494
    #   Rename the TEMP file, so that the tgz file creation appears atomic
495
    if ($cmdRv eq 0 && -f $tfileTmp) {
496
        rename $tfileTmp, $tfile || $logger->warn("Rename error: $tfileTmp");
497
    }
498
 
7389 dpurdie 499
 
500
    #
501
    #   Display the size of the package (tarZipped)
502
    #       Diagnostic use
503
    #
504
    if ( -f $tfile && $conf->{txdetail}) {
505
        my $tzfsize = -s $tfile; 
506
        my $size = sprintf "%.3f", $tzfsize / 1024 / 1024 / 1024 ;
507
        my $duration = time - $startTime;
508
        $logger->logmsg("tarZipPackage: Stats: $pname, $version, $size Gb, $duration Secs");
509
    }
510
 
511
 
7387 dpurdie 512
    if ( -f $tfile ) {
513
        $statistics{txCount}++;
514
        $logger->verbose2("tarZipPackage:Done: $pname/$version");
515
        $cmdRv = 1;
516
    } else {
517
        unlink $tfileTmp;
518
        $statistics{linkErrors}++;
519
        $logger->verbose2("tarZipPackage:Error: $pname/$version");
520
        $cmdRv = 0;
521
    }
522
 
523
    #
524
    # Return 0 if the required tar file exists
525
    #   
526
    return $cmdRv;
527
}
528
 
529
#-------------------------------------------------------------------------------
530
# Function        : triggerTransfers 
531
#
532
# Description     : Trigger transfers for other blat tasks that may be waiting for this
533
#                   tarZip to have been performed
534
#
535
# Inputs          : $pname
536
#                   $version 
537
#
538
# Returns         : Even less 
539
#
540
sub triggerTransfers
541
{
542
    my ($pname, $version) = @_;
543
 
544
    #
545
    #   Find the tag in all blat transfer areas
546
    #   
547
    my $tag = "$pname::$version";
548
    my @tagList = glob ("$tagRoot/*/$tag");
7389 dpurdie 549
    $logger->verbose2("triggerTransfer: $tagRoot/*/$tag: @tagList");
7387 dpurdie 550
    foreach my $target ( @tagList )
551
    {
552
        $logger->verbose2("triggerTransfer: $target");
553
        $target =~ m~^(.*)/~;
554
        my $triggerFile = catfile($1, '.trigger');
555
        Utils::TouchFile($conf, $triggerFile);
556
    }
557
}
558
 
559
#-------------------------------------------------------------------------------
560
# Function        : resetDailyStatistics 
561
#
562
# Description     : Called periodically to reset the daily statistics
563
#
564
# Inputs          : $time       - Current time
565
#
566
# Returns         : 
567
#
568
sub resetDailyStatistics
569
{
570
    my ($time) = @_;
571
 
572
    #
573
    #   Detect a new day
574
    #
575
    my $today = (localtime($time))[7];
576
    if ($yday != $today)
577
    {
578
        $yday = $today;
579
        $logger->logmsg('Resetting daily statistics' );
580
 
581
        # Note: Must match @recoverTags in readStatistics
582
        $statistics{dayStart} = $time;
583
        $statistics{txCount} = 0;
584
        $statistics{delCount} = 0;
585
        $statistics{staleTags} = 0;
586
        $statistics{linkErrors} = 0;
587
    }
588
}
589
 
590
#-------------------------------------------------------------------------------
591
# Function        : readStatistics 
592
#
593
# Description     : Read in the last set of stats
594
#                   Used after a restart to recover daily statistics
595
#
596
# Inputs          : 
597
#
598
# Returns         : 
599
#
600
sub readStatistics
601
{
602
    my @recoverTags = qw(dayStart txCount delCount staleTags linkErrors);
603
 
604
    if ($conf->{'statsfile'} and -f $conf->{'statsfile'})
605
    {
606
        if (open my $fh, $conf->{'statsfile'})
607
        {
608
            while (<$fh>)
609
            {
610
                m~(.*):(.*)~;
611
                if ( grep( /^$1$/, @recoverTags ) ) 
612
                {
613
                    $statistics{$1} = $2;
614
                    $logger->verbose("readStatistics $1, $2");
615
                }
616
            }
617
            close $fh;
618
            $yday = (localtime($statistics{dayStart}))[7];
619
        }
620
    }
621
}
622
 
623
 
624
#-------------------------------------------------------------------------------
625
# Function        : periodicStatistics 
626
#
627
# Description     : Called on a regular basis to write out statistics
628
#                   Used to feed information into Nagios
629
#                   
630
#                   This function is called via an alarm and may be outside the normal
631
#                   processing loop. Don't make assumptions on the value of $now
632
#
633
# Inputs          : 
634
#
635
# Returns         : 
636
#
637
sub periodicStatistics
638
{
639
    #
640
    #   A few local stats
641
    #
642
    $statistics{SeqNum}++;
643
    $statistics{timeStamp} = time();
644
    $statistics{upTime} = $statistics{timeStamp} - $startTime;
645
 
646
    #   Reset daily accumulations - on first use each day
647
    resetDailyStatistics($statistics{timeStamp});
648
 
649
    #
650
    #   Write statistics to a file
651
    #       Write to a tmp file, then rename.
652
    #       Attempt to make the operation atomic - so that the file consumer
653
    #       doesn't get a badly formed file.
654
    #   
655
    if ($conf->{'statsfiletmp'})
656
    {
657
        my $fh;
658
        unless (open ($fh, '>', $conf->{'statsfiletmp'}))
659
        {
660
            $fh = undef;
661
            $logger->warn("Cannot create temp stats file: $!");
662
        }
663
        else
664
        {
665
            foreach my $key ( sort { lc($a) cmp lc($b) } keys %statistics)
666
            {
667
                print $fh $key . ':' . $statistics{$key} . "\n";
668
                $logger->verbose2('Statistics:'. $key . ':' . $statistics{$key});
669
            }
670
            close $fh;
671
 
672
            # Rename temp to real file
673
            rename  $conf->{'statsfiletmp'},  $conf->{'statsfile'} ;
674
        }
675
    }
676
}
677
 
678
#-------------------------------------------------------------------------------
679
# Function        : sighandlers
680
#
681
# Description     : Install signal handlers
682
#
683
# Inputs          : $conf           - System config
684
#
685
# Returns         : Nothing
686
#
687
sub sighandlers
688
{
689
    my $conf = shift;
690
    my $logger = $conf->{logger};
691
 
692
    $SIG{TERM} = sub {
693
        # On shutdown
694
        $logger->logmsg('Received SIGTERM. Shutting down....' );
695
        unlink $conf->{'pidfile'} if (-f $conf->{'pidfile'});
696
        exit 0;
697
    };
698
 
699
    $SIG{HUP} = sub {
700
        # On logrotate
701
        $logger->logmsg('Received SIGHUP.');
702
        $logger->rotatelog();
703
    };
704
 
705
    $SIG{USR1} = sub {
706
        # On Force Cache Clean
707
        $logger->logmsg('Received SIGUSR1.');
708
        $lastCleanScan = 0;
709
    };
710
 
711
    alarm 60;
712
    $SIG{ALRM} = sub {
713
        # On Dump Statistics
714
        $logger->verbose2('Received SIGUSR2.');
715
        periodicStatistics();
716
        alarm 60;
717
    };
718
 
719
    $SIG{__WARN__} = sub { $logger->warn("@_") };
720
    $SIG{__DIE__} = sub { $logger->err("@_") };
721
}
722
 
723
 
724
#-------------------------------------------------------------------------------
725
# Function        : Error, Verbose, Warning
726
#
727
# Description     : Support for JatsRmApi
728
#
729
# Inputs          : Message
730
#
731
# Returns         : Nothing
732
#
733
sub Error
734
{
735
    $logger->err("@_");
736
}
737
 
738
sub Verbose
739
{
740
    $logger->verbose2("@_");
741
}
742
 
743
sub Warning
744
{
745
    $logger->warn("@_");
746
}
747
 
748