Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Make graphite's /render/?.... urls copy-pastable #158

Merged
merged 2 commits into from

13 participants

Dennis Kaarsemaker Jeff Schroeder Christopher Johnston rolandow Jason Dixon Justin Mason rickrdvaughn Luke Venediger syepes Alistair King Christopher Bowman Denis Zhdanov Bruno Renié
Dennis Kaarsemaker

Links to graphite images are completely unpastable to jabber/irc/mail as
clients mangle the humongous urls. These commits add a url shortener that can
shorten any graphite url from /what/ever/.... to /S/.

It can be used manually by prepending /s to the url path, and I added a button
to the graphite composer that does this for you.

Dennis Kaarsemaker

Here's a screenshot of it in action:

shorturl

Jeff Schroeder
Collaborator

Haven't had a chance to test this yet, but I love the idea

Christopher Johnston
Dennis Kaarsemaker

Thanks for considering. It's already proving pretty useful here, so I'm going to add links to create short urls to graphplot pages etc. as well.

rolandow

How do I get this button to fetch the URL in my Graphite? I only have the first three buttons shown in the screenshot, missing the last two.

Jason Dixon
Owner

I'm not :-1: on this, but it seems like odd bedfellows (to me) to add a URL shortener into Graphite proper. I understand your hesitancy to leak URLs outside of your organization, but there's probably a better solution imho.

Dennis Kaarsemaker

It's certainly possible to use an external url shortener app, but it's the integration with the graphite UI that made it 1000% more useful for us than an external app. So my definition of 'better' is more integration :)

Dennis Kaarsemaker seveas closed this
Dennis Kaarsemaker seveas reopened this
Jason Dixon
Owner

I get the usability aspect of it, but it's a slippery slope if we start integrating bits that are tangentially helpful. By that logic we could add "send to" buttons for email, Campfire, Facebook, etc. Just because we can doesn't mean we should.

Again, I'm not :-1: on this, just trying to offer a voice of reason.

Jeff Schroeder
Collaborator

It does suck quite a bit to send graphite urls in emails or IM especially to users with brain dead email clients that get confused by urls with () in them. It also sucks in markdown. External URL shorteners no way, but a simple and integrated one would be much appreciated by some users.

When sending links to less technical users, this is very valuable.

Justin Mason

sniping from the bikesheds: fwiw, I've seen a similar feature in Amazon's internal graphite-like system to deal with unpasteably humungous URLs.

rickrdvaughn

++interest in this feature! Any chance it will be merged?

Jason Dixon
Owner

@SEJeff Have you gotten a chance to test this? It seems the community has spoken. :smirk:

Luke Venediger

I've seen what @jmason is talking about: their graphing front-end auto-shortifies the link and displays it on the page. As an interim step, it would be awesome if the "Direct URL" button on the Dashboard gave me a complete link, as opposed to everything except the scheme and host. Extra points for auto-highlighting the whole line as it appears.

Jeff Schroeder
Collaborator

@obfuscurity I've not yet, but am going to shortly when I get home (travelling right now) at the end of the week. I'm in Boston at the moment

Dennis Kaarsemaker

I just rebased the patches onto current master and pushed the result.

Dennis Kaarsemaker

Just a datapoint as to how useful it is for us: in the 4 months since we added this, 666 short urls were created.

Jason Dixon
Owner

Clearly this is the devil's work at hand. Smite thine feature! :fire:

Justin Mason

\m/

syepes

+1 This would be a great addition

Alistair King

I'd also love to see this added. Was just about to code it myself when i saw this.

Alistair King

I've been using this PR for a couple of months now and it has been really great - with one exception:
It seems that the default length for the URLField field type used in the model is 200 characters (https://docs.djangoproject.com/en/dev/ref/models/fields/#urlfield), a limit that I easily ran over with Graphite render URLs.

In fairness I only came across this problem after switching to a MySQL backend, so perhaps SQLite does not enforce this constraint?

To get around the problem I changed the url field type in url_shortener/models.py to "TextField" and then followed the alter table workaround described at http://code.djangoproject.com/ticket/2495 to trick MySQL and Django into playing nicely together when using a TextArea as part of a unique key.

I'm pretty new to django so I'm hoping there a better way to fix this.

Dennis Kaarsemaker

Hmm, it's entirely possible that I did a manual alter table after syncdb, table definition here is:

url_shortener_link | CREATE TABLE `url_shortener_link` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `url` text NOT NULL,
  `date_submitted` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1123 DEFAULT CHARSET=utf8 
Christopher Bowman

I cherry picked this into my branch and it appears to be usable after these two commits:
cbowman0@bb776c6
cbowman0@a5efba4

I will be testing more.

Justin Mason jmason referenced this pull request in grafana/grafana
Closed

Direct links to graphs #117

Jason Dixon
Owner

Sorry that this has languished for so long. If someone has the time and inclination to rebase this, I'd be happy to merge it.

seveas added some commits
Dennis Kaarsemaker seveas Add URL shortening views
Links to graphite images are completely unpastable to jabber/irc/mail as
clients mangle the humongous urls. These commits add a url shortener
that can shorten any graphite url from /what/ever/.... to
/S/something_short.

It can be used manually by prepending /s to any url. This will return a
shortened version of that url. Subsequent commits will integrate this
with the composer and dashboard, and maybe other places.
e776d83
Dennis Kaarsemaker seveas Integrate the URL shortener
- The composer gets a button to shorten the URL to the current graph.
- The menu that appears when clicking on a graph in the dashboard
  gets a similar item.
514446d
Dennis Kaarsemaker

I've pushed reworked commits based on todays master that include @cbowman0's changes.

Jason Dixon
Owner

Unless anyone has objections, I'd like to merge this in today or tomorrow. /cc @esc @brutasse @SEJeff

Jeff Schroeder
Collaborator

Please do, I for sure would use this functionality. I'd probably implement it differently, but this is entirely reasonable

Denis Zhdanov
Collaborator

Using that patch (backported to 0.9.12) in production, haven't any troubles, even on sqlite

Jason Dixon obfuscurity merged commit b69aeb3 into from
Justin Mason

awesome. thanks guys, looking forward to this ;)

Jason Dixon
Owner

Note that this is only in the master branch. I don't expect that we'd want to any significant features in the 0.9.x branch anytime soon; 0.9.13 is expected to be our last release from that branch. We'll focus on getting a 0.10 release from master after that.

Bruno Renié
Collaborator

It'd be nice to mention this change in the 0.10 release notes.

Denis Zhdanov deniszh referenced this pull request from a commit in deniszh/graphite-web
Denis Zhdanov deniszh Backport of PR #158 (URL shortener) to 0.9.x branch
Contains new icon from PR #922
a4402b4
Denis Zhdanov deniszh referenced this pull request
Merged

0.9.x url shortener #938

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Aug 10, 2014
  1. Dennis Kaarsemaker

    Add URL shortening views

    seveas authored
    Links to graphite images are completely unpastable to jabber/irc/mail as
    clients mangle the humongous urls. These commits add a url shortener
    that can shorten any graphite url from /what/ever/.... to
    /S/something_short.
    
    It can be used manually by prepending /s to any url. This will return a
    shortened version of that url. Subsequent commits will integrate this
    with the composer and dashboard, and maybe other places.
  2. Dennis Kaarsemaker

    Integrate the URL shortener

    seveas authored
    - The composer gets a button to shorten the URL to the current graph.
    - The menu that appears when clicking on a graph in the dashboard
      gets a similar item.
This page is out of date. Refresh to see the latest.
1  setup.py
View
@@ -85,6 +85,7 @@
'graphite.graphlot',
'graphite.metrics',
'graphite.render',
+ 'graphite.url_shortener',
'graphite.version',
'graphite.whitelist',
],
BIN  webapp/content/img/browser.png
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 webapp/content/js/composer_widgets.js
View
@@ -45,6 +45,7 @@ function createComposerWindow(myComposer) {
createToolbarButton('Select Recent Data', 'arrow1.gif', toggleWindow(createRecentWindow) ),
createToolbarButton('Open in GraphPlot', 'line_chart.png', function() { window.open('/graphlot/?' + Composer.url.queryString,'_blank') }),
createToolbarButton('Create from URL', 'link.png', toggleWindow(createURLWindow) ),
+ createToolbarButton('Short URL', 'browser.png', showShortUrl),
'-',
timeDisplay
];
@@ -260,6 +261,48 @@ function asDateString(dateObj) {
return dateObj.format('H:i_Ymd');
}
+/* Short url window */
+function showShortUrl() {
+ showUrl = function(options, success, response) {
+ if(success) {
+ var win = new Ext.Window({
+ title: "Graph URL",
+ width: 600,
+ height: 125,
+ layout: 'border',
+ modal: true,
+ items: [
+ {
+ xtype: "label",
+ region: 'north',
+ style: "text-align: center;",
+ text: "Short Direct URL to this graph"
+ }, {
+ xtype: 'textfield',
+ region: 'center',
+ value: window.location.origin + response.responseText,
+ editable: false,
+ style: "text-align: center; font-size: large;",
+ listeners: {
+ focus: function (field) { field.selectText(); }
+ }
+ }
+ ],
+ buttonAlign: 'center',
+ buttons: [
+ {text: "Close", handler: function () { win.close(); } }
+ ]
+ });
+ win.show();
+ }
+ }
+ Ext.Ajax.request({
+ method: 'GET',
+ url: '/s/render/?' + Composer.url.queryString,
+ callback: showUrl,
+ });
+}
+
/* "Recent Data" dialog */
function toggleWindow(createFunc) {
function toggler (button, e) {
46 webapp/content/js/dashboard.js
View
@@ -1865,6 +1865,52 @@ function graphClicked(graphView, graphIndex, element, evt) {
});
win.show();
}
+ }, {
+ xtype: 'button',
+ fieldLabel: "<span style='visibility: hidden'>",
+ text: "Short Direct URL",
+ width: 100,
+ handler: function () {
+ menu.destroy();
+ showUrl = function(options, success, response) {
+ if(success) {
+ var win = new Ext.Window({
+ title: "Graph URL",
+ width: 600,
+ height: 125,
+ layout: 'border',
+ modal: true,
+ items: [
+ {
+ xtype: "label",
+ region: 'north',
+ style: "text-align: center;",
+ text: "Short Direct URL to this graph"
+ }, {
+ xtype: 'textfield',
+ region: 'center',
+ value: window.location.origin + response.responseText,
+ editable: false,
+ style: "text-align: center; font-size: large;",
+ listeners: {
+ focus: function (field) { field.selectText(); }
+ }
+ }
+ ],
+ buttonAlign: 'center',
+ buttons: [
+ {text: "Close", handler: function () { win.close(); } }
+ ]
+ });
+ win.show();
+ }
+ }
+ Ext.Ajax.request({
+ method: 'GET',
+ url: '/s' + record.data.url,
+ callback: showUrl,
+ });
+ }
}]
});
1  webapp/graphite/app_settings.py
View
@@ -77,6 +77,7 @@
'graphite.dashboard',
'graphite.whitelist',
'graphite.events',
+ 'graphite.url_shortener',
'django.contrib.auth',
'django.contrib.sessions',
'django.contrib.admin',
0  webapp/graphite/url_shortener/__init__.py
View
No changes.
58 webapp/graphite/url_shortener/baseconv.py
View
@@ -0,0 +1,58 @@
+"""
+Convert numbers from base 10 integers to base X strings and back again.
+
+Original: http://www.djangosnippets.org/snippets/1431/
+
+Sample usage:
+
+>>> base20 = BaseConverter('0123456789abcdefghij')
+>>> base20.from_decimal(1234)
+'31e'
+>>> base20.to_decimal('31e')
+1234
+"""
+
+class BaseConverter(object):
+ decimal_digits = "0123456789"
+
+ def __init__(self, digits):
+ self.digits = digits
+
+ def from_decimal(self, i):
+ return self.convert(i, self.decimal_digits, self.digits)
+
+ def to_decimal(self, s):
+ return int(self.convert(s, self.digits, self.decimal_digits))
+
+ def convert(number, fromdigits, todigits):
+ # Based on http://code.activestate.com/recipes/111286/
+ if str(number)[0] == '-':
+ number = str(number)[1:]
+ neg = 1
+ else:
+ neg = 0
+
+ # make an integer out of the number
+ x = 0
+ for digit in str(number):
+ x = x * len(fromdigits) + fromdigits.index(digit)
+
+ # create the result in base 'len(todigits)'
+ if x == 0:
+ res = todigits[0]
+ else:
+ res = ""
+ while x > 0:
+ digit = x % len(todigits)
+ res = todigits[digit] + res
+ x = int(x / len(todigits))
+ if neg:
+ res = '-' + res
+ return res
+ convert = staticmethod(convert)
+
+bin = BaseConverter('01')
+hexconv = BaseConverter('0123456789ABCDEF')
+base62 = BaseConverter(
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz'
+)
5 webapp/graphite/url_shortener/models.py
View
@@ -0,0 +1,5 @@
+from django.db import models
+
+class Link(models.Model):
+ url = models.TextField()
+ date_submitted = models.DateTimeField(auto_now_add=True)
24 webapp/graphite/url_shortener/views.py
View
@@ -0,0 +1,24 @@
+from django.core.urlresolvers import reverse
+from django.shortcuts import get_object_or_404
+from django.http import HttpResponse, HttpResponsePermanentRedirect
+
+from graphite.url_shortener.baseconv import base62
+from graphite.url_shortener.models import Link
+import re
+
+def follow(request, link_id):
+ """Follow existing links"""
+ key = base62.to_decimal(link_id)
+ link = get_object_or_404(Link, pk=key)
+ return HttpResponsePermanentRedirect('/' + link.url)
+
+def shorten(request, path):
+ if request.META.get('QUERY_STRING', None):
+ path += '?' + request.META['QUERY_STRING']
+ # Remove _salt, _dc and _uniq to avoid creating many copies of the same URL
+ path = re.sub('&_(uniq|salt|dc)=[0-9.]+', "", path)
+
+ link, created = Link.objects.get_or_create(url=path)
+ link_id = base62.from_decimal(link.id)
+ url = reverse('graphite.url_shortener.views.follow', kwargs={'link_id': link_id})
+ return HttpResponse(url, content_type='text/plain')
2  webapp/graphite/urls.py
View
@@ -30,6 +30,8 @@
('^graphlot/', include('graphite.graphlot.urls')),
('^version/', include('graphite.version.urls')),
('^events/', include('graphite.events.urls')),
+ ('^s/(?P<path>.*)', 'graphite.url_shortener.views.shorten'),
+ ('^S/(?P<link_id>[a-zA-Z0-9]+)/?$', 'graphite.url_shortener.views.follow'),
('^$', 'graphite.browser.views.browser'),
)
urlpatterns += staticfiles_urlpatterns()
Something went wrong with that request. Please try again.