I thought I might share this since it took me a few minutes to look around and figure out how. I setup a basic chat logging and output script. See here for an example. http://pielayer.getonmylevel.ca/starbound.php Create a Cron job that does the following. Code: grep "Info: <" /home/linux64/starbound_server.log > /tmp/chat.txt Then create a PHP page with the following. PHP: <?PHP$file_handle = fopen("/tmp/chat.txt", "r");while (!feof($file_handle) ) {$line_of_text = fgets($file_handle);$parts = explode('Info: <', $line_of_text);print $parts [0] . $parts [1]. "<BR>";}fclose($file_handle);?>
Good tip. I expanded upon the php page a bit to give it a better layout. It will also start with the scrollbar at the bottom of the chat log instead of the top automatically. It will check for mouse movement. If there has been no mouse movement for more than 4 seconds, the page will refresh loading the latest chat. Added this over a pure refresh to make sure if someone is scrolling through chat the page does not get reloaded and they end up back at the bottom again. The scripts are commented and values can be easily edited. In addition the CSS at the top is prepared for use with an additional column to the left, as well as a footer, so the page can be expanded if one so chooses. So the page can be used as is, expanded, or stripped down to be more bare bones. Code: <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Netheril Starbound Server Page</title> <style type="text/css"> body{ margin:0; padding:0; line-height: 1.5em; } b{font-size: 110%;} em{color: red;} #maincontainer{ width: 840px; /*Width of main container*/ margin: 0 auto; /*Center container on page*/ } #topsection{ background: #FFFFFF; color: #000000; height: 90px; /*Height of top section*/ } #topsection h1{ margin: 0; padding-top: 15px; } #contentwrapper{ float: left; width: 100%; } #contentcolumn{ margin-left: 0px; /*Set left margin to LeftColumnWidth*/ margin-bottom: 0px; overflow-y:scroll; height: 600px; border-style:inset; border-width:4px; } #leftcolumn{ float: left; width: 200px; /*Width of left column*/ margin-left: -840px; /*Set left margin to -(MainContainerWidth)*/ background: #C8FC98; } #footer{ clear: left; width: 100%; background: black; color: #FFF; text-align: center; padding: 0px 0; } #footer a{ color: #FFFF80; } .innerdiv{ margin: 10px; /*Margins for inner DIV inside each column (to provide padding)*/ margin-top: 0; } </style> </head> <body onload="refreshOnIdle();" onmousemove="haltTimer();"> <script type="text/javascript"> /* This script causes the page to check for mouse moment, and if there has been none, load new chat automatically every 5 seconds. */ var lastEvent = new Date().getTime(); var threshold = 4000; /*How long to wait for mouse movement. */ function doReload(){ var now = (new Date()).getTime(); if (now - lastEvent > threshold){ window.location.reload(true); } } document.body.onmousemove=function(){ lastEvent = (new Date()).getTime(); }; window.setInterval(doReload, 1000); </script> <div id="maincontainer"> <div id="topsection"><div class="innerdiv"><h1>Insert your page header here</h1></div></div> <div id="contentwrapper"> <div id="contentcolumn"> <div class="innerdiv"> <?PHP $file_handle = fopen("/tmp/chat.txt", "r"); while (!feof($file_handle) ) { $line_of_text = fgets($file_handle); $parts = explode('Info: <', $line_of_text); print $parts [0] . $parts [1]. "<BR>"; } fclose($file_handle); ?> </div> </div> <script type="text/javascript"> /*This script causes the scrollbar to automatically go to the bottom of chat on page load/reload.*/ var objDiv = document.getElementById("contentcolumn"); objDiv.scrollTop = objDiv.scrollHeight; </script> </div> <div id="footer"></div> </div> </body> </html>
Woah nice! I whipped mine up real quick just so I could see what was going on but this is awesome. I plan to shamefully steal this!
I made further modifications, changing the initial grep script. I found that the way it is currently setup, it wipes out all of the old chat data anytime the server log is recreated, due to a server restart or so on. If you want to keep all chat logging you can use this instead: Code: while inotifywait -e modify /root/steam/starbound/linux64/starbound_server.log do tail -1 /root/steam/starbound/linux64/starbound_server.log | grep "Info: <" >> /log/chat.txt done To use this requires inotify-tools to be installed. The directories of course should be equal to your own as well. What this does is it watches the starbound_server.log file for changes. When it detects a change to the server file, it runs a tail on the most recent line only, and greps for chat. It then appends the chat to the /log/chat.txt file. Using ">" instead of ">>" does a complete replace of the existing file with new data, which is what causes the loss of old chat history. Using just grep with >> though is not a viable option either, as it will add the same data multiple times. So you end up with a chat log with more and more duplicate entries. Using this method I put together above will always make sure to only add new data to the bottom of the chat.txt file, but will not erase the current data. You would not want to run this as a cronjob either, but actually place it inside of a screen and run it.
To get it to automatically start place that code above into a file named what you like. I named mine logchat. Make it executable: chmod +x logchat Create a second file named whatever you like, I named mine starbound_chat_logging. Inside that file place the following, making sure to use your own directory structure and file name: Code: cd /root/steam/starbound screen -S ChatLog -d -m ./logchat Make it executable: chmod +x starbound_chat_logging Copy that file into /etc/init.d: cp /root/steam/starbound/starbound_chat_logging /etc/init.d/starbound_chat_logging Make the script auto-start with your server: update-rc.d starbound_chat_logging defaults The end. That will make the chat logging automatically start with your server inside of a screen named ChatLog. You can attach to the screen at any time to see what it is doing with: screen -r ChatLog You can kill the screen with: CTRL+C You can detach from the screen by pressing: CTRL+A then CTRL+D
There is actually an issue with the PHP but I have not been able to figure out a solution to fix it. With this PHP code in a matter of days my error log was filed with over 17gb of error messages. It appears as if the explode is causing a blank NULL value at the end which does not actually exist. This results in the error log being filled with: "PHP Notice: Undefined offset: 1 in /var/www/index.php on line 208" I can fix it multiple different ways without using explode, but then I do not get the names of the people who are chatting, only their messages, and the preceding "Info:". I seem to be having trouble getting the <name> data to display, even though its on the same line. Does anyone have any tips on how to address this?
I believe I figured it out. With a slight modification of the PHP, it now properly handles null values and no longer throws out warnings into the "/var/log/apache2/error.log" file. Before: PHP: <?PHP$file_handle = fopen("/tmp/chat.txt", "r");while (!feof($file_handle) ) {$line_of_text = fgets($file_handle);$parts = explode('Info: <', $line_of_text);print $parts [0] . $parts [1]. "<BR>";}fclose($file_handle);?> After: PHP: <?PHP$file_handle = fopen("/tmp/chat.txt", "r");while (!feof($file_handle) ) {$line_of_text = fgets($file_handle);$parts = array_pad(explode("Info: <", $line_of_text), 2, null);print $parts [0] . $parts [1]. "<BR>";}fclose($file_handle);?>
Doesn't that depend on all of the data you want to display being present in the log file ? grep is being used to parse the chat data out of the server log which is wiped on a regular basis, into its own file, that can then be displayed with PHP and is never cleared automatically. At least in my modification. The original post of course does wipe the file, so this suggestion would be good. To use preg_match() and no grep at all, then the chat log would only parse the current file, and lose all historical chat. Unless I am misunderstanding the suggestion. This current way also ends up with a text file that includes all of the chat.
So replace the grep with a copy? If your log file is being cleared you should probably have a backup of it anyway. I confess, I've not yet poked the server side of things so I wasn't aware that the log file got cleared. How often is it cleared? Is it periodically or only on a server restart?
Why replace the grep with a copy though, the only information needed is chat logging, not all the extra information that is pretty much useless warnings right now. The base log file right now has no time stamps, and tons of virtually useless information. Using PHP to parse through the entire log file instead of a file that contains only the chat text seems inefficient. Especially for a server that has ran for a long time. It is filled with information like this: Code: Warn: Perf: UniverseServer::run.innerloop millis: 211 Info: Connection received from: 0000:0000:0000:0000:0000:0000:0000:0000 Info: Sending Handshake Challenge Warn: Perf: UniverseServer::handleQueuedConnection.handshake millis: 157 Info: Loading ship world received from client <3> Warn: Object boosterflame does not have a price set Warn: Object smallboosterflame does not have a price set Warn: Object teleporter does not have a price set Warn: Object hylotlshiplocker does not have a price set Warn: Object apexfuelhatch does not have a category set Warn: Object apexfuelhatch does not have a price set Warn: Object apexcaptainschair does not have a price set Info: Loading world db for world alpha:27066771:75683948:-10297482:11:5 Warn: Object flowerblue does not have a price set Warn: Perf: UniverseServer::createWorld millis: 190 Info: Client <3> connected Warn: Perf: UniverseServer::run.innerloop millis: 238 Warn: Perf: UniverseServer::doTriggeredStorage millis: 157 Warn: Perf: UniverseServer::run.innerloop millis: 258 Warn: Object wildcarrotseed does not have a price set Warn: Perf: UniverseServer::run.innerloop millis: 239 Warn: Object wildcarrotseed does not have a price set Warn: Perf: UniverseServer::doTriggeredStorage millis: 167 Warn: Perf: UniverseServer::run.innerloop millis: 268 Warn: Object wildcarrotseed does not have a price set Warn: Object wildcarrotseed does not have a price set Warn: Object wildcarrotseed does not have a price set Warn: Perf: UniverseServer::run.innerloop millis: 242 Warn: Perf: UniverseServer::run.innerloop millis: 216 Warn: Object smallboosterflame does not have a price set Warn: Object apexcaptainschair does not have a price set Warn: Object apexfuelhatch does not have a category set Warn: Object apexfuelhatch does not have a price set Warn: Object boosterflamehuman does not have a price set Warn: Object apexshiplocker does not have a price set Just tons and tons of useless info. No names on the client connects, no time stamps, so on.
You are not escaping html characters. I can go on your server, type some nasty javascript in chat and have it run on your web page. run the chat through htmlspecialchars() before printing it. This is extremely important.
Why in god's name are you doing this in PHP if you're going to use the shell anyway? If you're going to parse the whole thing in your PHP, fair enough, but what you're doing baffles me. Code: tail -F starbound_server.log | sed -n 's/^Info:\s\+\(<[^>]\+>\)/\1/ p' If you're concerned about your log being too big, write a script to rotate it properly. It's not hard. Hell, just use logrotate. And escape your damn input. Users are evil and cannot be trusted. Servers like this are what my friends and I call "easy targets".
Thanks for the tips, adding the escaping of html characters and switching from an ionotifywait to the more simple tail command. I still want to have all of the chat in an individual text file on the server though, so I am going to output it to a separate file and read that with the php. The log being too big is not really a worry for me. I just want a single file that contains all of the historical chat from the server, and just the chat. My server is only given to direct, local, friends, not random folks on the internet who might come in and run javascript in chat, but since I have posted on here I suppose that some folks could log in and do things. Such a harsh tone in the post, heh.
Yea that's the route I was just heading down myself. Though my sed script is slightly more complex. Code: tail -F starbound_server.log | sed -n '/^Info: / { s/&/\&/ig s/</\</ig s/>/\>/ig x s/^.*$/date +"%G-%m-%d %H:%M:%S | "/ e G s/\n// p x } ' This will attach a time stamp to each line and escape the '<>&' characters so they don't cause issues on a web page.