Skip to content
Snippets Groups Projects
get_data 4 KiB
Newer Older
  • Learn to ignore specific revisions
  • Jeremy Nicklas's avatar
    Jeremy Nicklas committed
    #!/bin/env ruby
    
    #
    # Set options here
    #
    OUTPUT     = ENV["OUTPUT"] || "data.txt"
    API_KEY    = ENV["GOOGLE_API_KEY"] || "google_api_key.json"
    GA_PROFILE = ENV["GOOGLE_PROFILE"] || "133342836"    # Open OnDemand (beta) / Authenticated Users
    START_DATE = ENV["START_DATE"]     || "2016-11-29"   # Server side analytics code deployed in OSC OnDemand production
    END_DATE   = ENV["END_DATE"]       || "today"        # google keyword is "today"
    START_STEP = ENV["START_STEP"]     || 1              # google starts with 1, NOT 0
    STEP_SIZE  = ENV["STEP_SIZE"]      || 10000          # max google step is 10,000
    # max 7 dimensions
    DIMENSIONS = %w(
      ga:dimension3
      ga:dimension1
      ga:dimension2
      ga:pagePath
    )
    USR_COLUMN = 1    # ga:dimension1
    APP_COLUMN = 3    # ga:pagePath
    # at least 1 metric, max 10 metrics
    METRICS    = %w(
      ga:hits
    )
    SORT       = %w()
    FILTERS    = %w(
    
      ga:hostname==ondemand.osc.edu;ga:dimension6==200
    
    Jeremy Nicklas's avatar
    Jeremy Nicklas committed
    )
    # Fix app token from page path
    APP_BASE_URI = "/pun"
    APP_TOKEN = {
      %r{^/sys/vncsim/sys/bc_osc_abaqus}                          => "sys/abaqus_cae",
      %r{^/sys/vncsim/sys/bc_osc_ansys_workbench}                 => "sys/ansys_workbench",
      %r{^/sys/vncsim/sys/bc_osc_comsol}                          => "sys/comsol",
      %r{^/sys/vncsim/sys/bc_osc_oakley_desktop}                  => "sys/oakley_desktop",
      %r{^/sys/vncsim/sys/bc_osc_oakley_vdi}                      => "sys/oakley_vdi",
      %r{^/sys/vncsim/sys/bc_osc_paraview}                        => "sys/paraview",
      %r{^/sys/vncsim/sys/bc_osc_ruby_desktop}                    => "sys/ruby_desktop",
      %r{^/sys/vncsim/sys/bc_osc_ruby_vdi}                        => "sys/ruby_vdi",
      %r{^/sys/vncsim/sys/(?<app_name>[^/]+)}                     => "sys/vncsim/sys/%{app_name}",
      %r{^/sys/vncsim/usr/(?<app_owner>[^/]+)/(?<app_name>[^/]+)} => "sys/vncsim/usr/%{app_owner}/%{app_name}",
      %r{^/sys/vncsim/dev/(?<app_name>[^/]+)}                     => "sys/vncsim/dev/%{user}/%{app_name}",
      %r{^/sys/(?<app_name>[^/]+)}                                => "sys/%{app_name}",
      %r{^/usr/(?<app_owner>[^/]+)/(?<app_name>[^/]+)}            => "usr/%{app_owner}/%{app_name}",
      %r{^/dev/(?<app_name>[^/]+)}                                => "dev/%{user}/%{app_name}"
    }
    
    #
    # Do not modify below
    #
    
    require 'rubygems'
    require 'bundler/setup'
    
    require 'googleauth'
    require 'google/apis/analytics_v3'
    
    credentials = Google::Auth::ServiceAccountCredentials.make_creds(
      json_key_io: File.open(API_KEY, 'r'),
      scope: Google::Apis::AnalyticsV3::AUTH_ANALYTICS_READONLY
    )
    
    analytics = Google::Apis::AnalyticsV3::AnalyticsService.new
    analytics.authorization = credentials
    
    class InvalidToken < StandardError; end
    
    def parse_uri(str, **opts)
      raise RuntimeError, "failed to parse app uri: #{str}" unless m = /^#{APP_BASE_URI}(?<app_uri>.+)$/.match(str)
      parse_token m[:app_uri], **opts
    end
    
    def parse_token(str, user: "")
      APP_TOKEN.each do |regex, token|
        if m = regex.match(str)
          return token % Hash[m.names.map(&:to_sym).zip(m.captures)].merge(user: user)
        end
      end
      raise InvalidToken, "failed to parse app token: #{str}"
    end
    
    def gather_data(analytics, file)
      target = open(file, "w")
      puts "Sending request..."
      start_index = START_STEP
      loop do
        results = analytics.get_ga_data(
          "ga:#{GA_PROFILE}",
          START_DATE,
          END_DATE,
          METRICS.join(','),
          dimensions:  DIMENSIONS.empty? ? nil : DIMENSIONS.join(','),
          filters:     FILTERS.empty?    ? nil : FILTERS.join(','),
          sort:        SORT.empty?       ? nil : SORT.join(','),
          start_index: start_index,
          max_results: STEP_SIZE
        )
        puts "Outputting #{results.rows.size} items..."
        results.rows.each do |row|
          begin
            app = row[APP_COLUMN]
            row[APP_COLUMN] = parse_uri(app, user: row[USR_COLUMN])
            row << app
            target.write "#{row.join(' ')}\n"
          rescue InvalidToken => e
            $stderr.puts "Warning: #{e.message}"
          end
        end
        start_index += STEP_SIZE
        break unless results.next_link
      end
      puts "Done!"
    ensure
      target.close
    end
    
    gather_data(analytics, OUTPUT)