Logging all Bro streams - bro

I want to log all the streams the Bro has to offer. I did the following for one stream but I am not getting the desired answer.
redef LogAscii::use_json=T;
redef LogAscii::json_timestamps = JSON::TS_ISO8601;
export
{
# Append the value LOG to the Log::ID enumerable.
redef enum Log::ID += { LOG };
}
event bro_init()
{
#Create the logging stream
Log::create_stream(LOG, [$columns=IRC::Info, $path="irc"]);
Log::write(LOG, IRC::Info) ;
}
Can I get any help with this?

Are you feeding traffic into Bro? Bro will only creates log files when it generates a log line which would go into that log.
Your script doesn't execute either, you are try to pass a type (IRC::Info) into a field that expects a value of that type.
You also don't need to call Log::create_stream, it is part of the base IRC support which is loaded by default.

Related

Redis StackExchange LuaScripts with parameters

I'm trying to use the following Lua script using C# StackExchange library:
private const string LuaScriptToExecute = #"
local current
current = redis.call(""incr"", KEYS[1])
if current == 1 then
redis.call(""expire"", KEYS[1], KEYS[2])
return 1
else
return current
end
Whenever i'm evaluating the script "as a string", it works properly:
var incrementValue = await Database.ScriptEvaluateAsync(LuaScriptToExecute,
new RedisKey[] { key, ttlInSeconds });
If I understand correctly, each time I invoke the ScriptEvaluateAsync method, the script is transmitted to the redis server which is not very effective.
To overcome this, I tried using the "prepared script" approach, by running:
_setCounterWithExpiryScript = LuaScript.Prepare(LuaScriptToExecute);
...
...
var incrementValue = await Database.ScriptEvaluateAsync(_setCounterWithExpiryScript,
new[] { key, ttlInSeconds });
Whenever I try to use this approach, I receive the following error:
ERR Error running script (call to f_7c891a96328dfc3aca83aa6fb9340674b54c4442): #user_script:3: #user_script: 3: Lua redis() command arguments must be strings or integers
What am I doing wrong?
What is the right approach in using "prepared" LuaScripts that receive dynamic parameters?
If I look in the documentation: no idea.
If I look in the unit test on github it looks really easy.
(by the way, is your ttlInSeconds really RedisKey and not RedisValue? You are accessing it thru KEYS[2] - shouldnt that be ARGV[1]? Anyway...)
It looks like you should rewrite your script to use named parameters and not arguments:
private const string LuaScriptToExecute = #"
local current
current = redis.call(""incr"", #myKey)
if current == 1 then
redis.call(""expire"", #myKey, #ttl)
return 1
else
return current
end";
// We should load scripts to whole redis cluster. Even when we dont have any.
// In that case, there will be only one EndPoint, one iteration etc...
_myScripts = _redisMultiplexer.GetEndPoints()
.Select(endpoint => _redisMultiplexer.GetServer(endpoint))
.Where(server => server != null)
.Select(server => lua.Load(server))
.ToArray();
Then just execute it with anonymous class as parameter:
for(var setCounterWithExpiryScript in _myScripts)
{
var incrementValue = await Database.ScriptEvaluateAsync(
setCounterWithExpiryScript,
new {
myKey: (RedisKey)key, // or new RedisKey(key) or idk
ttl: (RedisKey)ttlInSeconds
}
)// .ConfigureAwait(false); // ? ;-)
// when ttlInSeconds is value and not key, just dont cast it to RedisKey
/*
var incrementValue = await
Database.ScriptEvaluateAsync(
setCounterWithExpiryScript,
new {
myKey: (RedisKey)key,
ttl: ttlInSeconds
}
).ConfigureAwait(false);*/
}
Warning:
Please note that Redis is in full-stop mode when executing scripts. Your script looks super-easy (you sometimes save one trip to redis (when current != 1) so i have a feeling that this script will be counter productive in greater-then-trivial scale. Just do one or two calls from c# and dont bother with this script.
First of all, Jan's comment above is correct.
The script line that updated the key's TTL should be redis.call(""expire"", KEYS[1], ARGV[1]).
Regarding the issue itself, after searching for similar issues in RedisStackExchange's Github, I found that Lua scripts do not work really well in cluster mode.
Fortunately, it seems that "loading the scripts" isn't really necessary.
The ScriptEvaluateAsync method works properly in cluster mode and is sufficient (caching-wise).
More details can be found in the following Github issue.
So at the end, using ScriptEvaluateAsync without "preparing the script" did the job.
As a side note about Jan's comment above that this script isn't needed and can be replaced with two C# calls, it is actually quite important since this operation should be atomic as it is a "Rate limiter" pattern.

How does node-redis method setex() convert Buffer to string?

I'm using node-redis and I was hoping that someone could help me to figure out how this library converts Buffer to string. I gzip my data before I store it in redis with node-gzip and this call returns Promise<Buffer>
const data = JSON.stringify({ data: 'test' });
const compressed = await gzip(data, { level: 9 });
I tested following 2 approaches of saving buffer data into redis
Without .toString() - I pass the Buffer to the library and it will take care of the conversion
const result = await redisClient.setex('testKey', 3600, compressed);
and with .toString()
const result = await redisClient.setex('testKey', 3600, compressed.toString());
When I try these 2 approaches I don't get the same value saved in redis. I tried to use different params for .toString() to match the output of 1) but it didn't work
Reason why I need the saved value in 1) format is that I'm matching value format that what one of php pages generates
My code is working fine without .toString() but I would like to know how node-redis handles it internally
I've tried to find the answer in the source code and to debug and step into library calls but I didn't find the answer that I was looking for and I hope that someone can help me with this
It looks like happens in utils.js file:
utils.js
if (reply instanceof Buffer) {
return reply.toString();
}
Also use the proper options (i.e. return_buffers):
node-redis README
redis.createClient({ return_buffers: true });

Print SSRSReport to file (.PDF)

I need to find a way to "print" a SrsReport, in my case SalesInvoice, as .PDF (or any kind of file) to a specific location.
For this I modified the SRSPrintDestinationSettings to output the SalesInvoice-Report as a .PDF:
settings = controller.parmReportContract().parmPrintSettings();
settings.printMediumType(SRSPrintMediumType::File);
settings.fileFormat(SRSReportFileFormat::PDF);
settings.overwriteFile(true);
settings.fileName(#'\\AXDEV\Bottomline\Test\test.pdf');
Somehow this gets ignored and I recive a Email with the report as .PDF attached.
For example this will run on ax 2012 but won't print to PDF for me.
SRSPrintDestinationSettings settings;
CustInvoiceJour custInvoiceJour;
SrsReportRunController controller = new SrsReportRunController();
PurchPurchaseOrderContract rdpContract = new PurchPurchaseOrderContract();
SalesInvoiceContract salesInvoiceContract = new SalesInvoiceContract();
select firstOnly1 * from custInvoiceJour where custInvoiceJour.SalesId != "";
// Define report and report design to use
controller.parmReportName(ssrsReportStr(SalesInvoice,Report));
// Use execution mode appropriate to your situation
controller.parmExecutionMode(SysOperationExecutionMode::Synchronous);
rdpContract.parmRecordId(custInvoiceJour.RecId);
controller.parmReportContract().parmRdpContract(rdpContract);
// Explicitly provide all required parameters
salesInvoiceContract.parmRecordId(custInvoiceJour.RecId); // Record id must be passed otherwise the report will be empty
controller.parmReportContract().parmRdpContract(salesInvoiceContract);
salesInvoiceContract.parmCountryRegionISOCode(SysCountryRegionCode::countryInfo()); // comment this code if tested in pre release
// Change print settings as needed
settings = controller.parmReportContract().parmPrintSettings();
settings.printMediumType(SRSPrintMediumType::File);
settings.fileFormat(SRSReportFileFormat::PDF);
settings.overwriteFile(true);
settings.fileName(#'\\AXDEV\Bottomline\Test\test.pdf');
//tokens = settings as SrsPrintDestinationTokens();
//controller.parmPrintDestinationTokens(null);
//Suppress report dialog
controller.parmShowDialog(false);
// Execute the report
controller.startOperation();
Questions:
Is this the correct way to print a srsReport to .pdf?
Am I passing/setting the printerSettings correctly?
Where does it say "Send Email"?
EDIT: Code is working fine. We are using external code of a company which simply doesnt implement this.
Use the cleaner code of Alex Kwitny
Here is working code for me. I just quickly coded this from scratch/memory based off of glancing at yours, so compare for differences.
I have two things marked (1) and (2) for you to try with your code, or just copy/paste mine.
static void JobSendToPDFInvoice(Args _args)
{
SrsReportRunController controller = new SrsReportRunController();
SRSPrintDestinationSettings settings;
CustInvoiceJour custInvoiceJour = CustInvoiceJour::findRecId(5637925275);
SalesInvoiceContract salesInvoiceContract = new SalesInvoiceContract();
Args args = new Args();
controller.parmReportName(ssrsReportStr(SalesInvoice, Report));
controller.parmExecutionMode(SysOperationExecutionMode::Synchronous);
controller.parmShowDialog(false);
salesInvoiceContract.parmRecordId(custInvoiceJour.RecId);
salesInvoiceContract.parmDocumentTitle(CustInvoiceJour.InvoiceId);
salesInvoiceContract.parmCountryRegionISOCode(SysCountryRegionCode::countryInfo());
// (1) Try by passing args
args.record(custInvoiceJour);
args.parmEnum(PrintCopyOriginal::Original);
args.parmEnumType(enumNum(PrintCopyOriginal));
controller.parmReportContract().parmRdpContract(salesInvoiceContract);
controller.parmArgs(args);
// (2) Try explicitly preventing loading from last value
// controller.parmLoadFromSysLastValue(false);
// Change print settings as needed
settings = controller.parmReportContract().parmPrintSettings();
settings.printMediumType(SRSPrintMediumType::File);
settings.fileFormat(SRSReportFileFormat::PDF);
settings.overwriteFile(true);
settings.fileName(#'C:\Temp\Invoice.pdf');
controller.startOperation();
}
Since you are talking about the sales invoice the report is using the print management feature and you cannot simply override the print settings like that.
You need to override the runPrintMgmt on the controller class and determine there whether you want default print management or your own code.
See this post for an example: http://www.winfosoft.com/blog/microsoft-dynamics-ax/manipulating-printer-settings-with-x

FileHelper library - custom error messages

I am use the FileHelper to parse CSV files. Error messages encountered when parsing the file are displayed to the end user. The end user may not be able to make sense of the technical error message. Not too many clerks know what an Int32 is or Class: UploadFooDto.
I would like to customize the error messages so they are more user friendly. Something like:
Line 1. Column 2. A string (a) was entered instead of a number
Line 2. Column 3. '13-14-15' is not a valid date
I cannot find anything in the API that would allow me to customize the error messages. The most I have so far are some extension methods to clean up the errors:
public static class FileHelperExceptionExtensions
{
public static string BuildMessage(this ErrorInfo error)
{
if (error.ExceptionInfo is ConvertException)
{
return ((ConvertException)error.ExceptionInfo).BuildMessage();
}
if (error.ExceptionInfo is BadUsageException)
{
var message = error.ExceptionInfo.Message;
var readTo = message.IndexOf("Class:");
return message.Substring(0, readTo);
}
return string.Format("Line: {0}. An unspecific error occured.", error.LineNumber);
}
public static string BuildMessage(this ConvertException exception)
{
return string.Format("Line: {0}. Column: {1}. Field: {2}. Cannot convert '{3}' to type: '{4}'", exception.LineNumber, exception.ColumnNumber, exception.FieldName, exception.FieldStringValue, exception.FieldType.Name);
}
}
but these extensions still leave a lot to be desired. Is it possible to customize the error messages?
It's hard to improve on your extension methods without it being more hassle than it's worth.
You cannot subclass the default converters (e.g., FileHelpers.ConvertHelpers.Int32Converter since they are internal and sealed). You could create your own custom converter for each type (and base it on the corresponding source code from FileHelpers, e.g., Int32Converter). Then you can raise an alternative to ConvertException (also sealed so you cannot subclass) which would format the message differently.

dynamic file path in log4php

I am new to log4php.
I would like to save the log files in the format /logs/UserId/Info_ddmmyyyy.php
where the UserId is dynamic data.
(I would basically like to save one log per user.)
Is there any way to change the log file path dynamically?
This behaviour is not supported by default. But you can extend LoggerAppenderFile (or RollingFile, DailyFile whatever your preference is) to support it.
Create your own class for that and make it load to your script.
Then extend from this class:
http://svn.apache.org/repos/asf/logging/log4php/trunk/src/main/php/appenders/LoggerAppenderFile.php
class MyAppender extends LoggerAppenderFile { ... }
You'll need to overwrite the setFile() method, similar to:
public function setFile($file) {
$path = getYourFullPath();
$this->file = $path.$file;
}
After all you need to use your new Appender in you config
log4php.appender.myAppender = MyAppender
log4php.appender.myAppender.layout = LoggerLayoutSimple
log4php.appender.myAppender.file = my.log
Please note, instead of giving your full path to the log file you now need to add a plain name. The full path (including username) must be calculated with your getYourFullPath() method.
Hope that helps!
Christian