My multi-line logging events all end up multi-events - one event per line. According to the documentation:
Each call to LambdaLogger.log() results in a CloudWatch Logs event...
but then:
However, note that AWS Lambda treats each line returned by System.out
and System.err as a separate event.
Looking inside LambdaAppender's source code, it seems that it proceeds to log the event to System.out anyway. So does that mean multi-line messages will always be broken down into multiple event?
I have read about configuring the multi_line_start_pattern, but that seems only applicable when you get to deploy a log agent, which isn't accessible in Lambda.
[Edit] LambdaAppender logs to LambdaLogger which logs to System.out.
[Edit] I found some post where a workaround was suggested - use '\r' for the eol when printing the messages. This seems to work for messages that my code produces. Stack traces logged everywhere are still a problem.
[Edit] I have been using two workarounds:
Log complex data structures (e.g. sizable maps) in JSON. CloudWatch actually recognizes JSON strings in log events, and pretty print them.
Replace '\n' with '\r'. For stack traces I created a utility method (this is in Kotlin, but the idea is generic enough):
fun formatThrowable(t: Throwable): String {
val buffer = StringWriter()
t.printStackTrace(PrintWriter(buffer))
return buffer.toString().replace("\n", "\r")
}
I think in the long run a more ideal solution would be an Appender implementation that decorates ConsoleAppender, which would do the \r replacement on all messages passing through.
Best practice is to use json in your logs. Instead of sending multiline outputs, send a formatted json (regardless of the language you are using, you will find a lib that already does that for you)
You will be amazed how easy it gets to browse your logs from there. For instance, aws cloudwatch insights automatically detects your fields, it allow to parse them and query them within seconds
I suggest to use the project slf4j-simple-lambda and to refer to this blog for more explanations.
Using slf4j and slf4j-simple-lambda is solving elegantly your problem and the solution stay lightweight. The project includes the usage of the parameter org.slf4j.simpleLogger.newlineMethod which is there to solve this problem. By default, its value is auto and should be able to detect automatically the need for manual newline handling.
Discloser: I am co-author of slf4j-simple-lambda and author of the blog.
Related
Hey I m using MessageRoutingCallback to route to a function in spring cloud functions. It needs FunctionRoutingResult for routing. I also wanted to edit the message. The spring cloud docs says.
"Additionally, the FunctionRoutingResult provides another constructor allowing you to provide an instance of Message as second argument to be used down stream".
But the problem is the constructor with Message type in FunctionRoutingResult is internal and cannot be accessed outside.
Am I doing something wrong here. Any insight would be helpful
Couple of things.
As the documentation explains it is made to assist with routing decisions. For example if routing decision should be made based on payload which may need to be temporarily converted.
The reality is that it is a very bad practice to let framework make such decisions based on the payload, since payload is a privileged information. Similar to the letter in the envelope where mailman does not read the actual letter to make proper routing decisions. .. those all come from the envelope itself. So I will actually update the documentation to remove that paragraph.
And it is definitely not there to modify the message. That would be improper use of MessageRoutingCallback. To modify message you can use function composition. For example MessageRoutingCallback you check some header in the incoming message, determined that the function name should be foo but then actually output modifier|foo as function definition.
I have a trigger which acts after 3 checks of ping. Interval of checks 3 minutes.
I need to send message like:
Host unavailable from [time of first unsuccessfully check];
Trigger [time of trigger acts]
Which macros i need to use?
With the comment about scripts I'll offer the following.
Configuration/Actions allow you to specify the content of a message. That message can be thought of as simply passing parameters to something. The easy default is that it sends email, but the same parameters can be passed to a script.
Inside the Operations section, you specify the operation as to whom to send (again, think of this as a parameter), and what media type. The user/groups become a parameter as well.
Under Administration, Media types, you can define a media type of "Script". This invokes an external script you write, and passes to it parameters, which by default the first three are the send-to, subject, and message content. You can (in later Zabbix versions) include other parameters there as well (I do not recall if there is a limit). Before that, I started just passing any data I wanted in a predictable and delimited fashion in the message body, then I parse it out inside my script.
Inside the script itself, you pick up the strings passed in, and do whatever you want. So if one parameter (subject, explicitly a 4th+ parameter, or buried in a predictable place inside the body of the message) is a time, you can then operate on that time in the language of your choice, replace it, expound upon it, etc. Then when you have what you want, you send the message from within the script as desired.
Different actions can send using different media types, so you could do a script only for certain types of triggers, based on the conditions written in the action (e.g. a specific trigger name). So you can use default behavior for some, and custom-write other triggers as desired. The key is to have predictable format in the Config/Action/Triggers, and depend on that format in the Administration/Media types parameters, and inside the script they call. Don't forget to make the script accessible to the zabbix service account and place in the location specified in the zabbix config file. I find it useful to stick with an email-format, then I can "test" my actions by just emailing them, take the resulting email and use it to call my scripts outside of zabbix and ensure they work.
The ability to extend the default alerts by using scripts (and in turn a callable interface to zabbix server itself that can pull additional data from zabbix at script execution) makes alerting a bit arcane, but incredibly powerful. In general you can dynamically include almost anything, including graphs, in the alerts by reacting to the script parameters, and pulling together data to email.
I am a little confused about the invocation flow of action sequence. I read the code, it shows that each sequence has a main action, which invoke each action in that sequence. In each invocation, the main action will issue an post to apihost, does it means the whole flow(from controller->kafka->dispather->invoker->container) will go through again and again?
Update:
Quite recently (per ca15c68d348a2a02cf9da54475e96b43d48a3dac) sequences got a huge overhaul. The "root" action mentioned below is no longer needed and invocation of all the actions is internally orchestrated by the controller itself.
Due to this change being quite recent (as of 21st of November 2016) this might not be deployed to all the production environments there are.
What you described is basically right. The "root" action serves as an orchestrator to the "leaf" actions. The root action invokes the leaf actions one by one through the usual API, thus repeating that flow over and over again.
Conceptually that is how one can implement a sequence directly. In this commit https://github.com/openwhisk/openwhisk/commit/ca15c68d348a2a02cf9da54475e96b43d48a3dac) the sequence "main" is internalized into the controller and bypasses repeated authentication and entitlement checks. Requests internally are still posted to Kafka since that makes them subject to load balancing.
I was wondering about the proper way to store state between sequence invocations in WSO2ESB. In other words, if I have a scheduled task that invokes sequence S, at the end of iteration 0 I want to store some String variable (lets' call it ID), and then I want to read this ID at the start (or in the middle) of iteration 1, and so on.
To be more precise, I want to get a list of new SMS messages from an existing service, Twilio to be exact. However, Twilio only lets me get messages for selected days, i.e. there's no way for me to say give me only new messages (since I last checked / newer than certain message ID). Therefore, I'd like to create a scheduled task that will query Twilio and pass only new messages via REST call to my service. In order to do this, my sequence needs to query Twilio and then go through the returned list of messages, and discard messages that were already reported in the previous invocation. Now, to do this I need to store some state between different task/sequence invocations, i.e. at the end of the sequence I need to store the ID of the newest message in the current batch. This ID can then be used in subsequent invocation to determine which messages were already reported in the previous invocation.
I could use DBLookup and DB Report mediators, but it seems like an overkill (using a database to store a single string) and not very performance friendly. On the other hand, as far as I can see Class mediators are instantiated as singletons, therefore I could create a custom Class mediator that would manage this state and filter the list of messages to be sent to my service. I am quite sure that this will work, but I was wondering if this is the way to go, or there might be a more elegant solution that I missed.
We can think of 3 options here.
Using DBLookup/Report as you've suggested
Using the Carbon registry to store the values (this again uses DBs in the back end)
Using a Custom mediator to hold the state and read/write it from/to properties
Out of these three, obviously the third one will deliver the best performance since everything will be in-memory. It's also quite simple to implement and sometime back I did something similar and wrote a blog post here.
But on the other hand, the first two options can keep the state even when the server crashes, if it's a concern for your use case.
Since esb 490 you can persist and read properties from registry using property mediator.
https://docs.wso2.com/display/ESB490/Property+Mediator
This is basically a question regarding file manipulation. I'm working on a Perl script that will run as a cron job that sends an email when certain values shows up on a web page, but does so only once until the value resets (it's a page of reports containing audits that show an alert when a report requires attention). I've figured out how to parse the page for alerts, I know how to send emails via Perl, I'm just having a hard time figuring out the logic for WHEN to send the email. I gather that a separate file (alerts.txt) will need to be created to store the reports that had an alert during the previous execution of the script. In that case you have 4 scenarios to handle in the script. 1) The report has an alert and isn't in alerts.txt (needs to be added). 2) The report doesn't have an alert but is in alerts.txt from a previous execution of the script (needs to be removed). 3) The report doesn't have an alert and isn't in alerts.txt (do nothing). 4) The report has an alert and is already in alerts.txt (do nothing).
Is this the best way to go about this? If so, what's the best way to implement scenarios #1 and #2 above?
I am assuming you've chosen not to use a database - which is valid in some situations but you may change your mind as your application grows.
The simplest method, is to use the Storable modules which comes built in with perl. Note, this produces non human readable formats but can store quite complex data structures;
#!/usr/bin/env perl
use Storable;
# Create some alerts data, and store it in a data file
my $alerts = {};
$alerts->{report_01} = 'alert';
$alerts->{report_02} = 'ok';
store $alerts, 'alerts.data';
# Read it back
my $prev_alerts = retrieve('alerts.data');
foreach my $key (keys %$prev_alerts) {
print "$key=$prev_alerts->{$key}\n";
}
If you desire a human readable format there are various options that support file based storage;
ini; Config::Tiny
xml; XML::Simple
csv; Text::CSV