1. When making a thread, please tag your thread accordingly using the menu to the left of the textfield where you name your thread where applicable. Server Advertisements and Mod Releases should be contained to their respective subforums.

Server Help Tools for server administration

Discussion in 'Multiplayer' started by Meuhmeuh, Dec 12, 2013.

  1. wolvern

    wolvern Orbital Explorer

    @nithon

    any way to include timestamps as yet?
     
  2. nithon

    nithon Seal Broken

    well there are no timestamps in the chatlog atm so you cant get "real" timestamps.

    You could write an api, which periodically checks the logfile (every minute or so) and stores new chat messages with timestamp, then query the api from your website to get "estimated" timestamps ... similar to what Seriallos is doing in his coffee script
     
  3. superkuh

    superkuh Intergalactic Tourist

    Here's a perl script I threw together that runs once through the full log and thereafter tails the log for single line changes. Because it watches the log in real time it can generate it's own timestamps for events. RIght now it generates a very simple html page that shows a timestamp, currently connected players, and the last chat line they have said. It requires the POE::Wheel::FollowTail module from CPAN. You can see an example at http://starbound.superkuh.com/players.html .

    Code:
    #!/usr/bin/perl
    # http://poe.perl.org/?POE_Cookbook/Watching_Logs
    use warnings;
    use strict;
    use POE qw( Wheel::FollowTail );
    
    # starbound
    my $servername = 'starbound.superkuh.com';
    my $logfile = '/home/superkuh/.local/share/Steam/SteamApps/common/Starbound/linux64/starbound_server.log';
    my $webpagefilepath = "/home/superkuh/limbo/www/players.html";
    my %players;
    
    my %logs_to_watch = (
      starbound => "$logfile"
    );
    
    # go through the history and set things up during intialization.
    starbound_backlog();
    
    # Start a session to watch the logs.
    POE::Session->create(
      inline_states => {
        _start => \&begin_watchers,
    
        # Handle records from each log differently.
    
        starbound_record  => \&starbound_got_record,
    
        # Handle log resets and errors the same way for each file.
        log_reset => \&generic_log_reset,
        log_error => \&generic_log_error,
      }
    );
    
    sub begin_watchers {
      my $heap = $_[HEAP];
      while (my ($service, $log_file) = each %logs_to_watch) {
        my $log_watcher = POE::Wheel::FollowTail->new(
          Filename  => $log_file,
          InputEvent => $service . "_record",
          ResetEvent => "log_reset",
          ErrorEvent => "log_error",
        );
        $heap->{services}->{$log_watcher->ID} = $service;
        $heap->{watchers}->{$log_watcher->ID} = $log_watcher;
      }
    }
    
    # Handle log resets the same way for each file.  Simply recognize that
    # the log file was reset.
    sub generic_log_reset {
      my ($heap, $wheel_id) = @_[HEAP, ARG0];
      my $service = $heap->{services}->{$wheel_id};
      print "--- $service log reset at ", scalar(gmtime), " GMT\n";
    }
    
    # Handle log errors the same way for each file.  Recognize that an
    # error occurred while watching the file, and shut the watcher down.
    # If this were a real log watcher, it would periodically try to resume
    # watching the log file.
    sub generic_log_error {
      my ($heap, $operation, $errno, $error_string, $wheel_id) =
        @_[HEAP, ARG0, ARG1, ARG2, ARG3];
      my $service = $heap->{services}->{$wheel_id};
      print "--- $service log $operation error $errno: $error_string\n";
      print "--- Shutting down $service log watcher.\n";
      delete $heap->{services}->{$wheel_id};
      delete $heap->{watchers}->{$wheel_id};
    }
    
    # Watch for joins and parts.
    sub starbound_got_record {
        my $log_record = $_[ARG0];
        my $date = getdate();
    
    # The requests are coming from INSIDE THE NETWORK!
    #  return if $log_record =~ /^127\.0\.0\.1/;
    #  return if $log_record =~ /^192\.168\.1\./;
     
        if ($log_record =~ /Client \'(.+)\' <(\d{1,4})> \((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5})\) connected/) {
        # Info: Client 'superkuh' <1> (127.0.0.1:51671) connected
            $players{$1}++;
        } elsif ($log_record =~ /Reaping client \'(.+)\' <(\d{1,4})> \((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5})\) connection/) {
        # Info: Reaping client 'superkuh' <1> (127.0.0.1:51671) connection
            $players{$1} = 0;
        } elsif ($log_record =~ /Info:  <(.+)> (.+)/) {
            my $hmplayer = $1;
            my $lastchat = $2;
            $lastchat =~ s/(<|>)//g;
    
            print "1: $hmplayer, 2: $lastchat\n";
            $lastchat = sanitize_text($lastchat);
           
            $players{$hmplayer} = $lastchat;
    
        }
    
        open (my $webpage, ">$webpagefilepath") or die "Can't write to webpage.\n$!;";
        my $count = scalar (keys %players);
        print $webpage "<p>Server [$servername]. There have been $count unique players so far.</p>\n<p>Currently connected players: </p>\n<ul>\n";
        foreach my $username (keys %players) {
            if ($players{$username}) {
                print $webpage "<li>$date : <b>$username</b>";
                if ($players{$username} =~ /\w+/) {
                    print $webpage " - " . $players{$username} . "</li>";
                } else {
                    print "</li>";
                }
            }
        }
        print $webpage "</ul>\n";
    
        print $webpage "<p>Previously connected players: </p>\n<ul>\n";
        foreach my $username (keys %players) {
            unless ($players{$username}) {
                print $webpage "<li>$date : <b>$username</b>";
                if ($players{$username} =~ /\w+/) {
                    print $webpage " - " . $players{$username} . "</li>";
                } else {
                    print "</li>";
                }
            }
        }
        print $webpage "</ul>";
       
        return;
    
    }
    
    sub starbound_backlog {
        open (my $log, "$logfile") or die "Can't open backlog. $!";
        while((defined (my $line = <$log>))) {
            if ($line =~ /Client \'(.+)\' <(\d{1,4})> \((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5})\) connected/) {
                $players{$1}++;
            } elsif ($line =~ /Reaping client \'(.+)\' <(\d{1,4})> \((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5})\) connection/) {
                $players{$1} = 0;
            }
        }
    }
    
    
    # Run the watchers.  The run() method will return after all the
    # watchers end.
    $poe_kernel->run();
    
    
    sub sanitize_text {
        my $text = shift;
        my $ok_chars = 'a-zA-Z0-9\,\-.\s\?\"\':/';
        my $ok_chars2 = 'a-zA-Z0-9\,\-.\s\?\"/';
        $text =~ s/[^$ok_chars]//go;
        return $text;
    }
    
    sub getdate {
        my @months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
        my @weekDays = qw(Sun Mon Tue Wed Thu Fri Sat Sun);
        my ($second, $minute, $hour, $dayOfMonth, $month, $yearOffset, $dayOfWeek, $dayOfYear, $daylightSavings) = gmtime();
        my $year = 1900 + $yearOffset;
        $second = sprintf("%02d",$second);
        $minute = sprintf("%02d",$minute);
        my $theGMTime = "$hour:$minute:$second, $weekDays[$dayOfWeek] $months[$month] $dayOfMonth, $year";
        return $theGMTime;
    }
     
    Last edited: Dec 16, 2013
  4. good tooolz thank you meuhmeuh
     
  5. wolvern

    wolvern Orbital Explorer

    if i get perl working with iis7 right... i'll use this but see about programming it to a txt file and then getting it out again to my status page :)
     
  6. superkuh

    superkuh Intergalactic Tourist

    You don't need perl working with iis7. This perl script is totally webserver agnostic. All it cares about is the file path to the logs and where you want the generated html file to be. The script runs in the background as it's own process.
     
  7. wolvern

    wolvern Orbital Explorer

    yeah... :rofl:

    by the time we finish with all this... do you think we'll have a comprehensive control panel? :rofl:
     
  8. danks_

    danks_ Existential Complex

    [​IMG]

    well, if I was able to do one, I'm pretty sure a better looking admin panel is achievable.
    (ignore the last 2 options, those are made by me and for me. this was based on Plndas changes to the log.class.php, which is why I have the chat admin and I added a moderator to the list, because why not.)

    I can't into log to mysql because my skills aren't that good and am too lazy, but if that ever comes out, I'm so going to try my best to get a good, nice, useful website out there. The only thing that pisses me off about this system right now, is having to restart the server for it to read the changes on whitelist and bans. If only we could do /reload accesscontrol or if it happened on it's own every so minuts ;'c

    Go Chucklefish, sooner or later we'll have it :D
     
    Last edited: Dec 17, 2013
  9. Plnda

    Plnda Industrial Terraformer

    you can always do dirty and add firewall rules, clients are still only tcp connections

    i have implemented, worlds explored too with there x and y coordinates ;) and everything is now read from the configs, maxplayers, port ect
     
    Last edited: Dec 17, 2013
    danks_ likes this.
  10. Leonick

    Leonick Master Chief

    This should really be a link to this in the OP since the "original" python script in there doesn't work anymore but this one does.
     
  11. SpikeTheSpaceCowboy

    SpikeTheSpaceCowboy Tentacle Wrangler

    If you're looking for something a little more robust, here is a set of admin tools i'm working on in python as well.
     
  12. BMZ_G

    BMZ_G Poptop Tamer

  13. SpikeTheSpaceCowboy

    SpikeTheSpaceCowboy Tentacle Wrangler

    oh wow that looks really nice. Yeah I don't expect to be the furthest in development at this point, finals week, holiday break coming up at work, ... stuff. ;p Does this work with both windows and linux servers? That's really my main focus, equal development and functionality for both, I'd say I'm about 90% there, just need some time this weekend to post final results.
     
  14. Wifiik

    Wifiik Void-Bound Voyager

    Nice! :)
     
  15. BMZ_G

    BMZ_G Poptop Tamer

    Oh its not a race or anything, just thought I would show my progress. And yes, it should for all intents and purposes work on Windows & Linux - everything is in python, from the front end web to the back end.

    I'm terrible at design so with PorkPi I thought why bother? Just a white page with all of the functionality and information, design can take a back seat for now.
     
  16. SpikeTheSpaceCowboy

    SpikeTheSpaceCowboy Tentacle Wrangler

    I like the cut of your gib ;p
     
  17. danks_

    danks_ Existential Complex

    you should update the gifthub then ;) hahaha
     
  18. Meuhmeuh

    Meuhmeuh Seal Broken

    I have Updated my script for client connection and disconection, the regexp has changed :)
    We now have the IP adresse at the connection, a good news for banning IP , no more iptable needed
     
  19. Zoeff

    Zoeff Intergalactic Tourist

    I'm unfamiliar with PHP and can't seem to get your script to run properly, Meuhmeuh. :( I'm just getting a blank page, even with error reporting on. >_<

    Is there anything else I have to edit apart from the $path ?

    EDIT: I should probably mention that I'm trying to use the one showing the players connected, server status etc :D
     
    Last edited: Dec 19, 2013
  20. wolvern

    wolvern Orbital Explorer

    Check is php is installed correctly?

    Blank pages are also usually due to missing ; at end of lines
     

Share This Page