Logging & Analytics
     For fun and profit
Let me tell you about a bug
Let me tell you about a bug


• ~2% of our customers were affected
Let me tell you about a bug


• ~2% of our customers were affected
• Resolved (WORKSFORME)
Let me tell you about a bug


• ~2% of our customers were affected
• Resolved (WORKSFORME)
• People will complain, but they won’t send
  me crash reports
Let me tell you about a bug


• ~2% of our customers were affected
• Resolved (WORKSFORME)
• People will complain, but they won’t send
  me crash reports
• Apple’s crash reporter shows no crashes
I wrote my own crash reporter
c
The confidence you get from finding out about every crash,
 anywhere in the world, is crucial to delivering a high quality
 product that needs to be used in the wild. For those of us in
  the consumer software business it's absolutely critical.You
can't rely on your customers to tell you about crashes—many
of them may not be technical enough, and most of them won't
 bother to take time off of their own important work to give
    you a useful crash report unless you make it completely
                    automatic. - Joel Spolsky
It’s 2012, don’t roll your own
         Use quincykit.net
And everybody lived
     happily ever after...
Until...
NSError *err = nil;
[somethingWithErr:&err];
if (err) {
  UIAlertView *errorAlertView =
  [[UIAlertView alloc]
  initWithTitle:@”Error” message:[err
  description] delegate:nil
  cancelButtonTitle:OK
  otherButtonTitles:nil];
  [errorAlertView show];
  [errorAlertView release];
}
NSError *err = nil;
[somethingWithErr:&err];
if (err) {
  UIAlertView *errorAlertView =
  [[UIAlertView alloc]
  initWithTitle:@”Error” message:[err
  description] delegate:nil
  cancelButtonTitle:OK
  otherButtonTitles:nil];
  [errorAlertView show];
  [errorAlertView release];
}
Or do I want one of these?
So I wrote an error logger
And everybody lived
     happily ever after...
Until...
I started maintaining
    non-iOS code



 http://github.com/drewcrawford/buildbot
I have too much noise
But not enough signal
But too much noise
But not enough signal
Within the same msg
Meanwhile...
How do I make money?

1. Customer hears about me
2. ????
3. Profit!
How do I make money?

1. Customer hears about me
2. ????              What’s going on here?
3. Profit!
Web Analytics
Web Analytics
• How many different times does a person
  visit my site before they convert?
Web Analytics
• How many different times does a person
  visit my site before they convert?
• How do my blog readers’ habits change
  over time?
Web Analytics
• How many different times does a person
  visit my site before they convert?
• How do my blog readers’ habits change
  over time?
• What indicators (referrers, time-on-site,
  months of loyalty) correlate to high quality
  users?
Web Analytics
• How many different times does a person
  visit my site before they convert?
• How do my blog readers’ habits change
  over time?
• What indicators (referrers, time-on-site,
  months of loyalty) correlate to high quality
  users?
• Can I prioritize sales leads automatically by
  their behavior on my site?
App Analytics
App Analytics
• Do websites, SEM ads, or product videos
  matter?
App Analytics
• Do websites, SEM ads, or product videos
  matter?
• What causes people to make an IAP?
App Analytics
• Do websites, SEM ads, or product videos
  matter?
• What causes people to make an IAP?
• Should the button be here or there?
App Analytics
• Do websites, SEM ads, or product videos
  matter?
• What causes people to make an IAP?
• Should the button be here or there?
• Is anyone really going to use this feature?
App Analytics
• Do websites, SEM ads, or product videos
  matter?
• What causes people to make an IAP?
• Should the button be here or there?
• Is anyone really going to use this feature?
• How many of my app users still use after 3
  days?
Nothing on this page
answers any questions
Anatomy of a useful page
Anatomy of a useful page
  HOW???
About Flurry
[FlurryAnalytics
startSession:@"1R1NQX1SPPWD7SDPI9WZ"];
    for(int i = 0; i < 5; i++) {
        [FlurryAnalytics logEvent:@"In for loop"
withParameters:[NSDictionary dictionaryWithObject:
[NSNumber numberWithInt:i] forKey:@"i"]];
    }
And then I waited
 several hours...
And all I got was
    this lousy summary
The world’s most
    worthless pie chart
In fairness, you can
export a few hundred records into Excel
But if you want full logs
       You’d better ask nicely
If only we had a machine
 that could process large quantities of data...
These are views
Not models. They draw pretty pictures. They’re not
                   your data.
It walks like raw data export
     It talks like raw data export
               But it’s not.

Look for yourself: http://mixpanel.com/docs/api-
  documentation/data-export-api#libs-python
We don't provide raw log exports at this
time. It is something we are considering
adding to our pipeline, so thanks for writing
in with the feature request. - Mixpanel
I’m not saying there’s a conspiracy to
keep you from getting real event logs
But don’t believe you can export your data until you
     actually download & check the damn logs
Meanwhile...
The epic unit test
•   I’m working on a complicated “big-data” project

•   The unit tests parse 100ks of points and take
    hours

•   When your compile-build-run-test loop is
    measured in hours, you debug from an execution
    trace, not by stepping through code

•   One day the 200MB+ execution traces wouldn’t
    upload to our bug tracker any more
The epic unit test

• I was building custom tools to parse through the
  huge log files and give me the info I needed to
  debug after-the-fact
• There’s a complicated system of macros
  controlling log levels of different components
The epic unit test

• Even with all these tools, rarely would I log the
  right things.
• Logging the wrong things costs me hours to re-
  run the test.
• Over and over again.
Bion has a similar problem




  on a different project
Meanwhile...
I read this article




http://journal.paul.querna.org/articles/2011/12/26/log-for-
                     machines-in-json/
What if instead of this


[Mon Dec 26 09:14:46 2011] [info] [client 50.57.61.4] File does
not exist: /var/www/no-such-file
We log this
{
    "timestamp": 1324830675.076,
    "status": "404",
    "short_message": "File does not exist: /var/www/no-such-file",
    "host": "ord1.product.api0",
    "facility": "httpd",
    "errno": "ENOENT",
    "remote_host": "50.57.61.4",
    "remote_port": "40100",
    "path": "/var/www/no-such-file",
    "uri": "/no-such-file",
    "level": 4,
    "headers": {
        "user-agent": "BadAgent/1.0",
        "connection": "close",
        "accept": "*/*"
    },
    "method": "GET",
    "unique_id": ".rh-g2Tm.h-ord1.product.api0.r-axAIO3bO.c-9210.ts-1324830675.v-24e946e"
}
And instead of logging
       to this
We log to this
Then I can query

• By any element in the JSON dictionary
• Across multiple tiers (client, server, web)
• Across platforms
• I can assign a unique ID to an iOS event
  and follow the API request across my whole
  stack
If it serves up all FB’s content
Pretty sure it can handle a few million print statements
Have you figured out
the common problem?
      we’re talking about




  EVENTS
•   printf / NSLog         •   e-mail received

•   server logs            •   sales inquiry

•   webapp logs            •   bug resolved

•   page view              •   User taps button

•   error                  •   unit test run

•   download notification   •   patch committed
Why do we need 10 systems
       to solve one problem?
Only four kinds of events


• Things logged only to stderr / console
• Things logged to a unified network log file
• Things somebody is notified about
• Things somebody gets woken up about
So about that server...
I’ve been playing with loggly

• So far, so good
• I downloaded the damn logs
• Events queryable in ~5s for me
• High-perf log import (raw sock available)
• Filter and query on a hadoop cluster console, a
  few gotchas but pretty neat
• I’m routlinely pushing up 100k events per day
  and I’m a tiny user
Searching by bug #
 across platforms
Do you really expect
me to build that dict?
 I just want to type NSLog(@”Something”);
The hardest part of this whole mess
        is figuring out what to log
           and actually logging it
Remember this?


 An event that happened three months ago can be the
most important thing to understand the events of today.
We can add state to
  our log statement

• dict.username = “Frank”
• log(“something”) //username=Frank
• log(“something”) //username=Frank

 To reduce the work
But we have to
 remember to undo it
• dict.username = “bill”
• begin_session(bill)
• log(“something”)
• begin_session(james)
• log(“something else”) //oops!
Kind of like memory
    management

• Balance malloc with free
• Balance retain with release
• Balance new with delete
But some memory is
   auto-managed
int i = 0;
{
    int j = 0;
    //can access j and i
}
//can access only i
Can we use a similar trick
    to build our logging dictionary?
JUCHE
      •   printf / NSLog
                           •   e-mail received


      •   server logs
                           •   sales inquiry


      •   webapp logs
                           •   bug resolved


      •   page view
                           •   User taps button


      •   error
                           •   unit test run


      •   download
                           •   patch committed
          notification


One library to rule them all
• iOS, Python
• iOS, Python
• Builds the dict with ease
• iOS, Python
• Builds the dict with ease
• Logs to stderr, loggly
Events are nested
Events are nested
        • Today
Events are nested
        • Today
         • Got up
Events are nested
        • Today
         • Got up
         • Made coffee
Events are nested
        • Today
         • Got up
         • Made coffee
         • Closed bugs
Events are nested
        • Today
         • Got up
         • Made coffee
         • Closed bugs
           • Bug 1
Events are nested
        • Today
         • Got up
         • Made coffee
         • Closed bugs
           • Bug 1
           • Bug 2
Events are nested
        • Today
         • Got up
         • Made coffee
         • Closed bugs
           • Bug 1
           • Bug 2
         • Had lunch
Events are scoped
                    • Today
                     • Got up
                     • Made coffee
                     • Closed bugs
                       • Bug 1
                       • Bug 2
                     • Had lunch
Inner items inherit the settings of outer items
for(int i = 0; i < 3; i++) {
            [JucheLog revolt:@"i",[NSString
stringWithFormat:@"%d",i],^{
                    JUCHE(JINFO,@"My awesome
loop");
              }];
          }
for(int i = 0; i < 3; i++) {

             [JucheLog revolt:@"i",[NSString stringWithFormat:@"%d",i],^{

                   JUCHE(JINFO,@"My awesome loop");

             }];

        }

|   [INFO] 19:12:11 My awesome loop i=0    juchelog.py:142

|   [INFO] 19:12:11 My awesome loop i=1    juchelog.py:142

|   [INFO] 19:12:11 My awesome loop i=2    juchelog.py:142
for i in range(0,3):

           with juche.revolution(i=i,eternal_president="kim-il-sun"):

               juche.info("Outer loop!")

               for j in range(0,2):

                    with juche.revolution(j=j):

                         juche.info("Inner loop!")

|   [INFO] 19:12:11 Outer loop! i=0 eternal_president=kim-il-sun   juchelog.py:147

|   |   [INFO] 19:12:11 Inner loop! j=0   juchelog.py:150

|   |   [INFO] 19:12:11 Inner loop! j=1   juchelog.py:150

|   [INFO] 19:12:11 Outer loop! i=1 eternal_president=kim-il-sun   juchelog.py:147

|   |   [INFO] 19:12:11 Inner loop! j=0   juchelog.py:150

|   |   [INFO] 19:12:11 Inner loop! j=1   juchelog.py:150

|   [INFO] 19:12:11 Outer loop! i=2 eternal_president=kim-il-sun   juchelog.py:147

|   |   [INFO] 19:12:11 Inner loop! j=0   juchelog.py:150

|   |   [INFO] 19:12:11 Inner loop! j=1   juchelog.py:150
|   [INFO] 19:12:11 Outer loop! i=0 eternal_president=kim-il-sun   juchelog.py:147

|   |   [INFO] 19:12:11 Inner loop! j=0   juchelog.py:150

|   |   [INFO] 19:12:11 Inner loop! j=1   juchelog.py:150

|   [INFO] 19:12:11 Outer loop! i=1 eternal_president=kim-il-sun   juchelog.py:147

|   |   [INFO] 19:12:11 Inner loop! j=0   juchelog.py:150

|   |   [INFO] 19:12:11 Inner loop! j=1   juchelog.py:150

|   [INFO] 19:12:11 Outer loop! i=2 eternal_president=kim-il-sun   juchelog.py:147

|   |   [INFO] 19:12:11 Inner loop! j=0   juchelog.py:150

|   |   [INFO] 19:12:11 Inner loop! j=1   juchelog.py:150



{"function": "__block_global_0", "who": "G88014V4XYK", "indent": "2",
"thread": "main", "eternal_president": "kim-il-sun", "i": "2", "app":
"com.dca.JucheLogTestMac", "j": "2", "version": "1", "file":
"JucheLogTests.m", "msg": "Inner loop!", "line": "44", "level":
"info"}
Call for contributors




http://github.com/drewcrawford/JucheLog
Call for contributors
                             Use the library




http://github.com/drewcrawford/JucheLog
Call for contributors
                               Use the library
                      See if it solves your problems




http://github.com/drewcrawford/JucheLog
Call for contributors
                               Use the library
                      See if it solves your problems
                            Critique the syntax




http://github.com/drewcrawford/JucheLog
Call for contributors
                               Use the library
                      See if it solves your problems
                            Critique the syntax
                      Critique the terminal output




http://github.com/drewcrawford/JucheLog
Call for contributors
                               Use the library
                      See if it solves your problems
                            Critique the syntax
                      Critique the terminal output
                        Port it to (PHP, RoR, JS...)




http://github.com/drewcrawford/JucheLog
Call for contributors
                               Use the library
                      See if it solves your problems
                            Critique the syntax
                      Critique the terminal output
                        Port it to (PHP, RoR, JS...)
                      Write convenience functions




http://github.com/drewcrawford/JucheLog
Call for contributors
                               Use the library
                      See if it solves your problems
                            Critique the syntax
                      Critique the terminal output
                        Port it to (PHP, RoR, JS...)
                      Write convenience functions
                           “Log every Y times”




http://github.com/drewcrawford/JucheLog
Call for contributors
                               Use the library
                      See if it solves your problems
                            Critique the syntax
                      Critique the terminal output
                        Port it to (PHP, RoR, JS...)
                      Write convenience functions
                           “Log every Y times”
                             Log+UIAlertView




http://github.com/drewcrawford/JucheLog
Call for contributors
                               Use the library
                      See if it solves your problems
                            Critique the syntax
                      Critique the terminal output
                        Port it to (PHP, RoR, JS...)
                      Write convenience functions
                           “Log every Y times”
                             Log+UIAlertView
                       Log more types (NSError)



http://github.com/drewcrawford/JucheLog
Call for contributors
                               Use the library
                      See if it solves your problems
                            Critique the syntax
                      Critique the terminal output
                        Port it to (PHP, RoR, JS...)
                      Write convenience functions
                           “Log every Y times”
                             Log+UIAlertView
                       Log more types (NSError)
                           streamlined opt-out


http://github.com/drewcrawford/JucheLog
So how evil is this?
I am not a lawyer
  And this is not legal advice
17.1 Apps cannot transmit data about a user without
obtaining the user's prior permission and providing the
user with access to information about how and where
                 the data will be used
Your EULA says
   Consent to Use of Data:You agree that Application
Provider may collect and use technical data and related
    information, including but not limited to technical
 information about Your device, system and application
 software, and peripherals, that is gathered periodically
 to facilitate the provision of software updates, product
support and other services to You (if any) related to the
 Licensed Application. Application Provider may use this
   information, as long as it is in a form that does not
  personally identify You, to improve its products or to
          provide services or technologies to You.
Don’t be evil
I use data
I use data
• To diagnose and fix bugs and crashes
I use data
• To diagnose and fix bugs and crashes
• To learn where users are getting stuck
I use data
• To diagnose and fix bugs and crashes
• To learn where users are getting stuck
• To learn what percentage of my customer
  base experiences issues
I use data
• To diagnose and fix bugs and crashes
• To learn where users are getting stuck
• To learn what percentage of my customer
  base experiences issues
• To plan new features and updates
I use data
• To diagnose and fix bugs and crashes
• To learn where users are getting stuck
• To learn what percentage of my customer
  base experiences issues
• To plan new features and updates
• To A/B test and see what people like
I use data
• To diagnose and fix bugs and crashes
• To learn where users are getting stuck
• To learn what percentage of my customer
  base experiences issues
• To plan new features and updates
• To A/B test and see what people like
• To understand my customers’ needs
I use data
• To diagnose and fix bugs and crashes
• To learn where users are getting stuck
• To learn what percentage of my customer
  base experiences issues
• To plan new features and updates
• To A/B test and see what people like
• To understand my customers’ needs
• Always for the benefit of the users
Not to sell to someone else
(Don’t even log personal data)
So
Get a good signal
Turn down the noise
Try out Juche
http://github.com/drewcrawford/JucheLog
Look for common problems
     and build common solutions
•   Tiny iOS Developer

•   Mix of contracts &
    products

•   Many other dev tools
    like JucheLog
Drew Crawford
http://drewcrawfordapps.com
drew@drewcrawfordapps.com


http://sealedabstract.com <--you should be reading this

Cross-platform logging and analytics

  • 1.
    Logging & Analytics For fun and profit
  • 2.
    Let me tellyou about a bug
  • 3.
    Let me tellyou about a bug • ~2% of our customers were affected
  • 4.
    Let me tellyou about a bug • ~2% of our customers were affected • Resolved (WORKSFORME)
  • 5.
    Let me tellyou about a bug • ~2% of our customers were affected • Resolved (WORKSFORME) • People will complain, but they won’t send me crash reports
  • 6.
    Let me tellyou about a bug • ~2% of our customers were affected • Resolved (WORKSFORME) • People will complain, but they won’t send me crash reports • Apple’s crash reporter shows no crashes
  • 7.
    I wrote myown crash reporter
  • 9.
  • 10.
    The confidence youget from finding out about every crash, anywhere in the world, is crucial to delivering a high quality product that needs to be used in the wild. For those of us in the consumer software business it's absolutely critical.You can't rely on your customers to tell you about crashes—many of them may not be technical enough, and most of them won't bother to take time off of their own important work to give you a useful crash report unless you make it completely automatic. - Joel Spolsky
  • 11.
    It’s 2012, don’troll your own Use quincykit.net
  • 12.
    And everybody lived happily ever after...
  • 13.
  • 14.
    NSError *err =nil; [somethingWithErr:&err]; if (err) { UIAlertView *errorAlertView = [[UIAlertView alloc] initWithTitle:@”Error” message:[err description] delegate:nil cancelButtonTitle:OK otherButtonTitles:nil]; [errorAlertView show]; [errorAlertView release]; }
  • 15.
    NSError *err =nil; [somethingWithErr:&err]; if (err) { UIAlertView *errorAlertView = [[UIAlertView alloc] initWithTitle:@”Error” message:[err description] delegate:nil cancelButtonTitle:OK otherButtonTitles:nil]; [errorAlertView show]; [errorAlertView release]; }
  • 16.
    Or do Iwant one of these?
  • 17.
    So I wrotean error logger
  • 18.
    And everybody lived happily ever after...
  • 19.
  • 20.
    I started maintaining non-iOS code http://github.com/drewcrawford/buildbot
  • 24.
    I have toomuch noise
  • 25.
  • 26.
  • 28.
  • 29.
  • 31.
  • 32.
    How do Imake money? 1. Customer hears about me 2. ???? 3. Profit!
  • 33.
    How do Imake money? 1. Customer hears about me 2. ???? What’s going on here? 3. Profit!
  • 34.
  • 35.
    Web Analytics • Howmany different times does a person visit my site before they convert?
  • 36.
    Web Analytics • Howmany different times does a person visit my site before they convert? • How do my blog readers’ habits change over time?
  • 37.
    Web Analytics • Howmany different times does a person visit my site before they convert? • How do my blog readers’ habits change over time? • What indicators (referrers, time-on-site, months of loyalty) correlate to high quality users?
  • 38.
    Web Analytics • Howmany different times does a person visit my site before they convert? • How do my blog readers’ habits change over time? • What indicators (referrers, time-on-site, months of loyalty) correlate to high quality users? • Can I prioritize sales leads automatically by their behavior on my site?
  • 39.
  • 40.
    App Analytics • Dowebsites, SEM ads, or product videos matter?
  • 41.
    App Analytics • Dowebsites, SEM ads, or product videos matter? • What causes people to make an IAP?
  • 42.
    App Analytics • Dowebsites, SEM ads, or product videos matter? • What causes people to make an IAP? • Should the button be here or there?
  • 43.
    App Analytics • Dowebsites, SEM ads, or product videos matter? • What causes people to make an IAP? • Should the button be here or there? • Is anyone really going to use this feature?
  • 44.
    App Analytics • Dowebsites, SEM ads, or product videos matter? • What causes people to make an IAP? • Should the button be here or there? • Is anyone really going to use this feature? • How many of my app users still use after 3 days?
  • 45.
    Nothing on thispage answers any questions
  • 46.
    Anatomy of auseful page
  • 47.
    Anatomy of auseful page HOW???
  • 49.
  • 50.
    [FlurryAnalytics startSession:@"1R1NQX1SPPWD7SDPI9WZ"]; for(int i = 0; i < 5; i++) { [FlurryAnalytics logEvent:@"In for loop" withParameters:[NSDictionary dictionaryWithObject: [NSNumber numberWithInt:i] forKey:@"i"]]; }
  • 51.
    And then Iwaited several hours...
  • 52.
    And all Igot was this lousy summary
  • 53.
    The world’s most worthless pie chart
  • 54.
    In fairness, youcan export a few hundred records into Excel
  • 55.
    But if youwant full logs You’d better ask nicely
  • 56.
    If only wehad a machine that could process large quantities of data...
  • 57.
    These are views Notmodels. They draw pretty pictures. They’re not your data.
  • 60.
    It walks likeraw data export It talks like raw data export But it’s not. Look for yourself: http://mixpanel.com/docs/api- documentation/data-export-api#libs-python
  • 61.
    We don't provideraw log exports at this time. It is something we are considering adding to our pipeline, so thanks for writing in with the feature request. - Mixpanel
  • 62.
    I’m not sayingthere’s a conspiracy to keep you from getting real event logs But don’t believe you can export your data until you actually download & check the damn logs
  • 63.
  • 64.
    The epic unittest • I’m working on a complicated “big-data” project • The unit tests parse 100ks of points and take hours • When your compile-build-run-test loop is measured in hours, you debug from an execution trace, not by stepping through code • One day the 200MB+ execution traces wouldn’t upload to our bug tracker any more
  • 65.
    The epic unittest • I was building custom tools to parse through the huge log files and give me the info I needed to debug after-the-fact • There’s a complicated system of macros controlling log levels of different components
  • 66.
    The epic unittest • Even with all these tools, rarely would I log the right things. • Logging the wrong things costs me hours to re- run the test. • Over and over again.
  • 67.
    Bion has asimilar problem on a different project
  • 68.
  • 69.
    I read thisarticle http://journal.paul.querna.org/articles/2011/12/26/log-for- machines-in-json/
  • 70.
    What if insteadof this [Mon Dec 26 09:14:46 2011] [info] [client 50.57.61.4] File does not exist: /var/www/no-such-file
  • 71.
    We log this {    "timestamp": 1324830675.076,     "status": "404",     "short_message": "File does not exist: /var/www/no-such-file",     "host": "ord1.product.api0",     "facility": "httpd",     "errno": "ENOENT",     "remote_host": "50.57.61.4",     "remote_port": "40100",     "path": "/var/www/no-such-file",     "uri": "/no-such-file",     "level": 4,     "headers": {         "user-agent": "BadAgent/1.0",         "connection": "close",         "accept": "*/*"     },     "method": "GET",     "unique_id": ".rh-g2Tm.h-ord1.product.api0.r-axAIO3bO.c-9210.ts-1324830675.v-24e946e" }
  • 72.
    And instead oflogging to this
  • 73.
  • 74.
    Then I canquery • By any element in the JSON dictionary • Across multiple tiers (client, server, web) • Across platforms • I can assign a unique ID to an iOS event and follow the API request across my whole stack
  • 75.
    If it servesup all FB’s content Pretty sure it can handle a few million print statements
  • 76.
    Have you figuredout the common problem? we’re talking about EVENTS
  • 77.
    printf / NSLog • e-mail received • server logs • sales inquiry • webapp logs • bug resolved • page view • User taps button • error • unit test run • download notification • patch committed
  • 78.
    Why do weneed 10 systems to solve one problem?
  • 79.
    Only four kindsof events • Things logged only to stderr / console • Things logged to a unified network log file • Things somebody is notified about • Things somebody gets woken up about
  • 80.
    So about thatserver...
  • 81.
    I’ve been playingwith loggly • So far, so good • I downloaded the damn logs • Events queryable in ~5s for me • High-perf log import (raw sock available) • Filter and query on a hadoop cluster console, a few gotchas but pretty neat • I’m routlinely pushing up 100k events per day and I’m a tiny user
  • 82.
    Searching by bug# across platforms
  • 83.
    Do you reallyexpect me to build that dict? I just want to type NSLog(@”Something”);
  • 84.
    The hardest partof this whole mess is figuring out what to log and actually logging it
  • 85.
    Remember this? Anevent that happened three months ago can be the most important thing to understand the events of today.
  • 86.
    We can addstate to our log statement • dict.username = “Frank” • log(“something”) //username=Frank • log(“something”) //username=Frank To reduce the work
  • 87.
    But we haveto remember to undo it • dict.username = “bill” • begin_session(bill) • log(“something”) • begin_session(james) • log(“something else”) //oops!
  • 88.
    Kind of likememory management • Balance malloc with free • Balance retain with release • Balance new with delete
  • 89.
    But some memoryis auto-managed int i = 0; { int j = 0; //can access j and i } //can access only i
  • 90.
    Can we usea similar trick to build our logging dictionary?
  • 91.
    JUCHE • printf / NSLog • e-mail received • server logs • sales inquiry • webapp logs • bug resolved • page view • User taps button • error • unit test run • download • patch committed notification One library to rule them all
  • 93.
  • 94.
    • iOS, Python •Builds the dict with ease
  • 95.
    • iOS, Python •Builds the dict with ease • Logs to stderr, loggly
  • 96.
  • 97.
  • 98.
    Events are nested • Today • Got up
  • 99.
    Events are nested • Today • Got up • Made coffee
  • 100.
    Events are nested • Today • Got up • Made coffee • Closed bugs
  • 101.
    Events are nested • Today • Got up • Made coffee • Closed bugs • Bug 1
  • 102.
    Events are nested • Today • Got up • Made coffee • Closed bugs • Bug 1 • Bug 2
  • 103.
    Events are nested • Today • Got up • Made coffee • Closed bugs • Bug 1 • Bug 2 • Had lunch
  • 104.
    Events are scoped • Today • Got up • Made coffee • Closed bugs • Bug 1 • Bug 2 • Had lunch Inner items inherit the settings of outer items
  • 105.
    for(int i =0; i < 3; i++) { [JucheLog revolt:@"i",[NSString stringWithFormat:@"%d",i],^{ JUCHE(JINFO,@"My awesome loop"); }]; }
  • 106.
    for(int i =0; i < 3; i++) { [JucheLog revolt:@"i",[NSString stringWithFormat:@"%d",i],^{ JUCHE(JINFO,@"My awesome loop"); }]; } | [INFO] 19:12:11 My awesome loop i=0 juchelog.py:142 | [INFO] 19:12:11 My awesome loop i=1 juchelog.py:142 | [INFO] 19:12:11 My awesome loop i=2 juchelog.py:142
  • 107.
    for i inrange(0,3): with juche.revolution(i=i,eternal_president="kim-il-sun"): juche.info("Outer loop!") for j in range(0,2): with juche.revolution(j=j): juche.info("Inner loop!") | [INFO] 19:12:11 Outer loop! i=0 eternal_president=kim-il-sun juchelog.py:147 | | [INFO] 19:12:11 Inner loop! j=0 juchelog.py:150 | | [INFO] 19:12:11 Inner loop! j=1 juchelog.py:150 | [INFO] 19:12:11 Outer loop! i=1 eternal_president=kim-il-sun juchelog.py:147 | | [INFO] 19:12:11 Inner loop! j=0 juchelog.py:150 | | [INFO] 19:12:11 Inner loop! j=1 juchelog.py:150 | [INFO] 19:12:11 Outer loop! i=2 eternal_president=kim-il-sun juchelog.py:147 | | [INFO] 19:12:11 Inner loop! j=0 juchelog.py:150 | | [INFO] 19:12:11 Inner loop! j=1 juchelog.py:150
  • 108.
    | [INFO] 19:12:11 Outer loop! i=0 eternal_president=kim-il-sun juchelog.py:147 | | [INFO] 19:12:11 Inner loop! j=0 juchelog.py:150 | | [INFO] 19:12:11 Inner loop! j=1 juchelog.py:150 | [INFO] 19:12:11 Outer loop! i=1 eternal_president=kim-il-sun juchelog.py:147 | | [INFO] 19:12:11 Inner loop! j=0 juchelog.py:150 | | [INFO] 19:12:11 Inner loop! j=1 juchelog.py:150 | [INFO] 19:12:11 Outer loop! i=2 eternal_president=kim-il-sun juchelog.py:147 | | [INFO] 19:12:11 Inner loop! j=0 juchelog.py:150 | | [INFO] 19:12:11 Inner loop! j=1 juchelog.py:150 {"function": "__block_global_0", "who": "G88014V4XYK", "indent": "2", "thread": "main", "eternal_president": "kim-il-sun", "i": "2", "app": "com.dca.JucheLogTestMac", "j": "2", "version": "1", "file": "JucheLogTests.m", "msg": "Inner loop!", "line": "44", "level": "info"}
  • 109.
  • 110.
    Call for contributors Use the library http://github.com/drewcrawford/JucheLog
  • 111.
    Call for contributors Use the library See if it solves your problems http://github.com/drewcrawford/JucheLog
  • 112.
    Call for contributors Use the library See if it solves your problems Critique the syntax http://github.com/drewcrawford/JucheLog
  • 113.
    Call for contributors Use the library See if it solves your problems Critique the syntax Critique the terminal output http://github.com/drewcrawford/JucheLog
  • 114.
    Call for contributors Use the library See if it solves your problems Critique the syntax Critique the terminal output Port it to (PHP, RoR, JS...) http://github.com/drewcrawford/JucheLog
  • 115.
    Call for contributors Use the library See if it solves your problems Critique the syntax Critique the terminal output Port it to (PHP, RoR, JS...) Write convenience functions http://github.com/drewcrawford/JucheLog
  • 116.
    Call for contributors Use the library See if it solves your problems Critique the syntax Critique the terminal output Port it to (PHP, RoR, JS...) Write convenience functions “Log every Y times” http://github.com/drewcrawford/JucheLog
  • 117.
    Call for contributors Use the library See if it solves your problems Critique the syntax Critique the terminal output Port it to (PHP, RoR, JS...) Write convenience functions “Log every Y times” Log+UIAlertView http://github.com/drewcrawford/JucheLog
  • 118.
    Call for contributors Use the library See if it solves your problems Critique the syntax Critique the terminal output Port it to (PHP, RoR, JS...) Write convenience functions “Log every Y times” Log+UIAlertView Log more types (NSError) http://github.com/drewcrawford/JucheLog
  • 119.
    Call for contributors Use the library See if it solves your problems Critique the syntax Critique the terminal output Port it to (PHP, RoR, JS...) Write convenience functions “Log every Y times” Log+UIAlertView Log more types (NSError) streamlined opt-out http://github.com/drewcrawford/JucheLog
  • 120.
    So how evilis this?
  • 121.
    I am nota lawyer And this is not legal advice
  • 122.
    17.1 Apps cannottransmit data about a user without obtaining the user's prior permission and providing the user with access to information about how and where the data will be used
  • 123.
    Your EULA says Consent to Use of Data:You agree that Application Provider may collect and use technical data and related information, including but not limited to technical information about Your device, system and application software, and peripherals, that is gathered periodically to facilitate the provision of software updates, product support and other services to You (if any) related to the Licensed Application. Application Provider may use this information, as long as it is in a form that does not personally identify You, to improve its products or to provide services or technologies to You.
  • 124.
  • 125.
  • 126.
    I use data •To diagnose and fix bugs and crashes
  • 127.
    I use data •To diagnose and fix bugs and crashes • To learn where users are getting stuck
  • 128.
    I use data •To diagnose and fix bugs and crashes • To learn where users are getting stuck • To learn what percentage of my customer base experiences issues
  • 129.
    I use data •To diagnose and fix bugs and crashes • To learn where users are getting stuck • To learn what percentage of my customer base experiences issues • To plan new features and updates
  • 130.
    I use data •To diagnose and fix bugs and crashes • To learn where users are getting stuck • To learn what percentage of my customer base experiences issues • To plan new features and updates • To A/B test and see what people like
  • 131.
    I use data •To diagnose and fix bugs and crashes • To learn where users are getting stuck • To learn what percentage of my customer base experiences issues • To plan new features and updates • To A/B test and see what people like • To understand my customers’ needs
  • 132.
    I use data •To diagnose and fix bugs and crashes • To learn where users are getting stuck • To learn what percentage of my customer base experiences issues • To plan new features and updates • To A/B test and see what people like • To understand my customers’ needs • Always for the benefit of the users
  • 133.
    Not to sellto someone else
  • 134.
    (Don’t even logpersonal data)
  • 135.
  • 136.
    Get a goodsignal
  • 137.
  • 138.
  • 139.
    Look for commonproblems and build common solutions
  • 140.
    Tiny iOS Developer • Mix of contracts & products • Many other dev tools like JucheLog
  • 141.